﻿<?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++博客-KISS(Keep It Simple, Standard)-随笔分类-MFC</title><link>http://www.cppblog.com/QUIRE-0216/category/4973.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 20 May 2008 02:02:49 GMT</lastBuildDate><pubDate>Tue, 20 May 2008 02:02:49 GMT</pubDate><ttl>60</ttl><item><title>VC常用数据类型使用转换详解 (转)</title><link>http://www.cppblog.com/QUIRE-0216/archive/2007/11/08/36114.html</link><dc:creator>QUIRE-0216</dc:creator><author>QUIRE-0216</author><pubDate>Thu, 08 Nov 2007 01:41:00 GMT</pubDate><guid>http://www.cppblog.com/QUIRE-0216/archive/2007/11/08/36114.html</guid><wfw:comment>http://www.cppblog.com/QUIRE-0216/comments/36114.html</wfw:comment><comments>http://www.cppblog.com/QUIRE-0216/archive/2007/11/08/36114.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/QUIRE-0216/comments/commentRss/36114.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/QUIRE-0216/services/trackbacks/36114.html</trackback:ping><description><![CDATA[<table style="BORDER-COLLAPSE: collapse; WORD-WRAP: break-word" cellSpacing=0 cellPadding=4 width=680 align=center border=0>
    <tbody>
        <tr>
            <td height=10></td>
        </tr>
        <tr>
            <td style="MARGIN: 8px; LINE-HEIGHT: 150%" width=680>
            <p style="MARGIN: 8px; LINE-HEIGHT: 150%">
            <p>刚接触VC编程的朋友往往对许多数据类型的转换感到迷惑不解，本文将介绍一些常用数据类型的使用。</p>
            <p>我们先定义一些常见类型变量借以说明</p>
            <p>int i = 100;<br>long l = 2001;<br>float f=300.2;<br>double d=12345.119;<br>char username[]="程佩君";<br>char temp[200];<br>char *buf;<br>CString str;<br>_variant_t v1;<br>_bstr_t v2;</p>
            <p>一、其它数据类型转换为字符串</p>
            <p><br>短整型(int)<br>itoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制<br>itoa(i,temp,2); ///按二进制方式转换 <br>长整型(long)<br>ltoa(l,temp,10); <br>浮点数(float,double)<br>用fcvt可以完成转换,这是MSDN中的例子:<br>int decimal, sign; <br>char *buffer; <br>double source = 3.1415926535; <br>buffer = _fcvt( source, 7, &amp;decimal, &amp;sign ); <br>运行结果:source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 0<br>decimal表示小数点的位置,sign表示符号:0为正数，1为负数 <br>CString变量<br>str = "2008北京奥运";<br>buf = (LPSTR)(LPCTSTR)str; <br>BSTR变量<br>BSTR bstrValue = ::SysAllocString(L"程序员"); <br>char * buf = _com_util::ConvertBSTRToString(bstrValue); <br>SysFreeString(bstrValue); <br>AfxMessageBox(buf); <br>delete(buf); <br>CComBSTR变量<br>CComBSTR bstrVar("test"); <br>char *buf = _com_util::ConvertBSTRToString(bstrVar.m_str); <br>AfxMessageBox(buf); <br>delete(buf); </p>
            <p>_bstr_t变量<br>_bstr_t类型是对BSTR的封装，因为已经重载了=操作符，所以很容易使用<br>_bstr_t bstrVar("test"); <br>const char *buf = bstrVar;///不要修改buf中的内容 <br>AfxMessageBox(buf); </p>
            <p><br>通用方法(针对非COM数据类型)<br>用sprintf完成转换<br>char&nbsp; buffer[200];<br>char&nbsp; c = '1';<br>int&nbsp;&nbsp; i = 35;<br>long&nbsp; j = 1000;<br>float f = 1.7320534f;<br>sprintf( buffer, "%c",c);<br>sprintf( buffer, "%d",i);<br>sprintf( buffer, "%d",j);<br>sprintf( buffer, "%f",f);</p>
            <p>二、字符串转换为其它数据类型<br>strcpy(temp,"123"); </p>
            <p>短整型(int)<br>i = atoi(temp); <br>长整型(long)<br>l = atol(temp); <br>浮点(double)<br>d = atof(temp); <br>CString变量<br>CString name = temp; <br>BSTR变量 <br>BSTR bstrValue = ::SysAllocString(L"程序员"); <br>...///完成对bstrValue的使用<br>SysFreeString(bstrValue); </p>
            <p>CComBSTR变量<br>CComBSTR类型变量可以直接赋值<br>CComBSTR bstrVar1("test");<br>CComBSTR bstrVar2(temp);</p>
            <p>_bstr_t变量<br>_bstr_t类型的变量可以直接赋值<br>_bstr_t bstrVar1("test"); <br>_bstr_t bstrVar2(temp); </p>
            <p><br>三、其它数据类型转换到CString<br>使用CString的成员函数Format来转换,例如:</p>
            <p><br>整数(int)<br>str.Format("%d",i); <br>浮点数(float)<br>str.Format("%f",i); <br>字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值<br>str = username; <br>对于Format所不支持的数据类型，可以通过上面所说的关于其它数据类型转化到char *的方法先转到char *，然后赋值给CString变量。</p>
            <p>四、BSTR、_bstr_t与CComBSTR</p>
            <p><br>CComBSTR 是ATL对BSTR的封装，_bstr_t是C++对BSTR的封装,BSTR是32位指针,但并不直接指向字串的缓冲区。<br>char *转换到BSTR可以这样: <br>BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上comutil.h和comsupp.lib<br>SysFreeString(bstrValue); <br>反之可以使用<br>char *p=_com_util::ConvertBSTRToString(b);<br>delete p;<br>具体可以参考一，二段落里的具体说明。</p>
            <p>CComBSTR与_bstr_t对大量的操作符进行了重载，可以直接进行=,!=,==等操作，所以使用非常方便。<br>特别是_bstr_t,建议大家使用它。</p>
            <p><br>五、VARIANT 、_variant_t 与 COleVariant</p>
            <p><br>VARIANT的结构可以参考头文件VC98\Include\OAIDL.H中关于结构体tagVARIANT的定义。<br>对于VARIANT变量的赋值：首先给vt成员赋值，指明数据类型，再对联合结构中相同数据类型的变量赋值，举个例子：<br>VARIANT va;<br>int a=2001;<br>va.vt=VT_I4;///指明整型数据<br>va.lVal=a; ///赋值</p>
            <p>对于不马上赋值的VARIANT，最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系:</p>
            <p>Byte bVal;&nbsp; // VT_UI1. <br>Short iVal;&nbsp; // VT_I2. <br>long lVal;&nbsp; // VT_I4. <br>float fltVal;&nbsp; // VT_R4. <br>double dblVal;&nbsp; // VT_R8. <br>VARIANT_BOOL boolVal;&nbsp; // VT_BOOL. <br>SCODE scode;&nbsp; // VT_ERROR. <br>CY cyVal;&nbsp; // VT_CY. <br>DATE date;&nbsp; // VT_DATE. <br>BSTR bstrVal;&nbsp; // VT_BSTR. <br>DECIMAL FAR* pdecVal&nbsp; // VT_BYREF|VT_DECIMAL. <br>IUnknown FAR* punkVal;&nbsp; // VT_UNKNOWN. <br>IDispatch FAR* pdispVal;&nbsp; // VT_DISPATCH. <br>SAFEARRAY FAR* parray;&nbsp; // VT_ARRAY|*. <br>Byte FAR* pbVal;&nbsp; // VT_BYREF|VT_UI1. <br>short FAR* piVal;&nbsp; // VT_BYREF|VT_I2. <br>long FAR* plVal;&nbsp; // VT_BYREF|VT_I4. <br>float FAR* pfltVal;&nbsp; // VT_BYREF|VT_R4. <br>double FAR* pdblVal;&nbsp; // VT_BYREF|VT_R8. <br>VARIANT_BOOL FAR* pboolVal;&nbsp; // VT_BYREF|VT_BOOL. <br>SCODE FAR* pscode;&nbsp; // VT_BYREF|VT_ERROR. <br>CY FAR* pcyVal;&nbsp; // VT_BYREF|VT_CY. <br>DATE FAR* pdate;&nbsp; // VT_BYREF|VT_DATE. <br>BSTR FAR* pbstrVal;&nbsp; // VT_BYREF|VT_BSTR. <br>IUnknown FAR* FAR* ppunkVal;&nbsp; // VT_BYREF|VT_UNKNOWN. <br>IDispatch FAR* FAR* ppdispVal;&nbsp; // VT_BYREF|VT_DISPATCH. <br>SAFEARRAY FAR* FAR* pparray;&nbsp; // VT_ARRAY|*. <br>VARIANT FAR* pvarVal;&nbsp; // VT_BYREF|VT_VARIANT. <br>void FAR* byref;&nbsp; // Generic ByRef. <br>char cVal;&nbsp; // VT_I1. <br>unsigned short uiVal;&nbsp; // VT_UI2. <br>unsigned long ulVal;&nbsp; // VT_UI4. <br>int intVal;&nbsp; // VT_INT. <br>unsigned int uintVal;&nbsp; // VT_UINT. <br>char FAR * pcVal;&nbsp; // VT_BYREF|VT_I1. <br>unsigned short FAR * puiVal;&nbsp; // VT_BYREF|VT_UI2. <br>unsigned long FAR * pulVal;&nbsp; // VT_BYREF|VT_UI4. <br>int FAR * pintVal;&nbsp; // VT_BYREF|VT_INT. <br>unsigned int FAR * puintVal;&nbsp; //VT_BYREF|VT_UINT. </p>
            <p><br>_variant_t是VARIANT的封装类，其赋值可以使用强制类型转换，其构造函数会自动处理这些数据类型。<br>使用时需加上#include &lt;comdef.h&gt;<br>例如：<br>long l=222;<br>ing i=100;<br>_variant_t lVal(l);<br>lVal = (long)i;</p>
            <p><br>COleVariant的使用与_variant_t的方法基本一样，请参考如下例子：<br>COleVariant v3 = "字符串", v4 = (long)1999;<br>CString str =(BSTR)v3.pbstrVal;<br>long i = v4.lVal;</p>
            <p><br>六、其它一些COM数据类型</p>
            <p>根据ProgID得到CLSID<br>HRESULT CLSIDFromProgID( LPCOLESTR lpszProgID,LPCLSID pclsid);<br>CLSID clsid;<br>CLSIDFromProgID( L"MAPI.Folder",&amp;clsid);</p>
            <p>根据CLSID得到ProgID<br>WINOLEAPI ProgIDFromCLSID( REFCLSID clsid,LPOLESTR * lplpszProgID); <br>例如我们已经定义了 CLSID_IApplication,下面的代码得到ProgID<br>LPOLESTR pProgID = 0;<br>ProgIDFromCLSID( CLSID_IApplication,&amp;pProgID);<br>...///可以使用pProgID <br>CoTaskMemFree(pProgID);//不要忘记释放 </p>
            <p>七、ANSI与Unicode<br>Unicode称为宽字符型字串,COM里使用的都是Unicode字符串。</p>
            <p>将ANSI转换到Unicode<br>(1)通过L这个宏来实现，例如: CLSIDFromProgID( L"MAPI.Folder",&amp;clsid);<br>(2)通过MultiByteToWideChar函数实现转换,例如:<br>char *szProgID = "MAPI.Folder";<br>WCHAR szWideProgID[128];<br>CLSID clsid;<br>long lLen = MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));<br>szWideProgID[lLen] = '\0'; <br>(3)通过A2W宏来实现,例如: <br>USES_CONVERSION; <br>CLSIDFromProgID( A2W(szProgID),&amp;clsid); <br>将Unicode转换到ANSI<br>(1)使用WideCharToMultiByte,例如:<br>// 假设已经有了一个Unicode 串 wszSomeString... <br>char szANSIString [MAX_PATH]; <br>WideCharToMultiByte ( CP_ACP, WC_COMPOSITECHECK, wszSomeString, -1, szANSIString, sizeof(szANSIString), NULL, NULL ); <br>(2)使用W2A宏来实现,例如:<br>USES_CONVERSION;<br>pTemp=W2A(wszSomeString); <br>八、其它</p>
            <p>对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据（DWORD)分解成两个16位数据（WORD),例如：<br>LPARAM lParam;<br>WORD loValue = LOWORD(lParam);///取低16位<br>WORD hiValue = HIWORD(lParam);///取高16位</p>
            <p><br>对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如:<br>WORD wValue;<br>BYTE loValue = LOBYTE(wValue);///取低8位<br>BYTE hiValue = HIBYTE(wValue);///取高8位</p>
            <p><br>两个16位数据（WORD）合成32位数据(DWORD,LRESULT,LPARAM,或WPARAM)<br>LONG MAKELONG( WORD wLow, WORD wHigh );<br>WPARAM MAKEWPARAM( WORD wLow, WORD wHigh ); <br>LPARAM MAKELPARAM( WORD wLow, WORD wHigh );<br>LRESULT MAKELRESULT( WORD wLow, WORD wHigh ); </p>
            <p><br>两个8位的数据(BYTE)合成16位的数据(WORD)<br>WORD MAKEWORD( BYTE bLow, BYTE bHigh ); </p>
            <p><br>从R(red),G(green),B(blue)三色得到COLORREF类型的颜色值<br>COLORREF RGB( BYTE byRed,BYTE byGreen,BYTE byBlue );<br>例如COLORREF bkcolor = RGB(0x22,0x98,0x34);</p>
            <p><br>从COLORREF类型的颜色值得到RGB三个颜色值<br>BYTE Red = GetRValue(bkcolor); ///得到红颜色<br>BYTE Green = GetGValue(bkcolor); ///得到绿颜色<br>BYTE Blue = GetBValue(bkcolor); ///得到兰颜色</p>
            <p><br>九、注意事项<br>假如需要使用到ConvertBSTRToString此类函数,需要加上头文件comutil.h,并在setting中加入comsupp.lib或者直接加上#pragma comment( lib, "comsupp.lib" )</p>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/QUIRE-0216/aggbug/36114.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/QUIRE-0216/" target="_blank">QUIRE-0216</a> 2007-11-08 09:41 <a href="http://www.cppblog.com/QUIRE-0216/archive/2007/11/08/36114.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MFC应用程序中指针的使用(转)</title><link>http://www.cppblog.com/QUIRE-0216/archive/2007/09/14/32198.html</link><dc:creator>QUIRE-0216</dc:creator><author>QUIRE-0216</author><pubDate>Fri, 14 Sep 2007 01:58:00 GMT</pubDate><guid>http://www.cppblog.com/QUIRE-0216/archive/2007/09/14/32198.html</guid><wfw:comment>http://www.cppblog.com/QUIRE-0216/comments/32198.html</wfw:comment><comments>http://www.cppblog.com/QUIRE-0216/archive/2007/09/14/32198.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/QUIRE-0216/comments/commentRss/32198.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/QUIRE-0216/services/trackbacks/32198.html</trackback:ping><description><![CDATA[<table cellSpacing=0 cellPadding=0 width="100%" border=0>
    <tbody>
        <tr>
            <td width=40 height=74></td>
            <td vAlign=top width=* height=74>
            <form name=form2 action=/SYS/script/find.asp method=post>
                <table cellSpacing=0 cellPadding=0 width="100%" border=0>
                    <tbody>
                        <tr>
                            <td><span id=docinfo></span></td>
                            <td align=right></td>
                        </tr>
                    </tbody>
                </table>
            </form>
            <table cellSpacing=0 cellPadding=0 width="100%" border=0>
                <tbody>
                    <tr>
                        <td>
                        <p align=center><strong>MFC应用程序中指针的使用</strong><br></p>
                        <a href="http://www.vckbase.com/document/viewdoc/?id=658#A1"><font color=#800080><u>1) 在View中获得Doc指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A2"><font color=#800080><u>2) 在App中获得MainFrame指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A3"><font color=#800080><u>3) 在View中获得MainFrame指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A4"><font color=#800080><u>4) 获得View（已建立）指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A5"><font color=#800080><u>5) 获得当前文档指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A6"><font color=#800080><u>6) 获得状态栏与工具栏指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A7"><font color=#800080><u>7) 获得状态栏与工具栏变量</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A8"><font color=#800080><u>8) 在Mainframe获得菜单指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A9"><font color=#800080><u>9) 在任何类中获得应用程序类</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A0"><font color=#800080><u>10) 从文档类取得视图类的指针(1)</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A10"><font color=#800080><u>11) 在App中获得文档模板指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A11"><font color=#800080><u>12) 从文档模板获得文档类指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A12"><font color=#800080><u>13) 在文档类中获得文档模板指针</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A13"><font color=#800080><u>14) 从文档类取得视图类的指针(2)</u></font></a><br><a href="http://www.vckbase.com/document/viewdoc/?id=658#A14"><u><font color=#800080>15) 从一个视图类取得另一视图类的指针</font></u></a><br><br>VC中编程对于刚刚开始学习的同学，最大的障碍和问题就是消息机制和指针获取与操作。其实这些内容基本上是每本VC学习工具书上必讲的内容，而且通过MSDN很多问题都能解决。<br>下面文字主要是个人在编程中指针使用的一些体会，说的不当的地方请指正。<br>一般我们使用的框架是VC提供的Wizard生成的MFC App Wizard(exe)框架，无论是多文档还是单文档，都存在指针获取和操作问题。<br>下面这节内容主要是一般的框架，然后再讲多线程中的指针使用。使用到的类需要包含响应的头文件。首先一般获得本类(视，文档，对话框都支持)实例指针this，用this的目的，主要可以通过类中的函数向其他类或者函数中发指针，以便于在非本类中操作和使用本类中的功能。<br><br><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a name=A1></a> 1） 在View中获得Doc指针
                        <pre>CYouSDIDoc *pDoc=GetDocument();一个视只能有一个文档。</pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A2 name=A2></a> 2) 在App中获得MainFrame指针<br>CWinApp 中的 m_pMainWnd变量就是MainFrame的指针<br>也可以：
                        <pre>CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd();</pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A3 name=A3></a> 3) 在View中获得MainFrame指针
                        <pre>CMainFrame *pMain=(CmaimFrame *)AfxGetApp()-&gt;m_pMainWnd;</pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A4 name=A4></a> 4) 获得View（已建立）指针
                        <pre>CMainFrame *pMain=(CmaimFrame *)AfxGetApp()-&gt;m_pMainWnd;
                        CyouView *pView=(CyouView *)pMain-&gt;GetActiveView();</pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A5 name=A5></a> 5) 获得当前文档指针
                        <pre>CDocument * pCurrentDoc =(CFrameWnd *)m_pMainWnd-&gt;GetActiveDocument();</pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A6 name=A6></a> 6) 获得状态栏与工具栏指针
                        <pre>CStatusBar * pStatusBar＝(CStatusBar *)AfxGetMainWnd()-&gt;GetDescendantWindow(AFX_IDW_STATUS_BAR);
                        CToolBar * pToolBar=(CtoolBar *)AfxGetMainWnd()-&gt;GetDescendantWindow(AFX_IDW_TOOLBAR);
                        </pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A7 name=A7></a> 7) 如果框架中加入工具栏和状态栏变量还可以这样
                        <pre>(CMainFrame *)GetParent()-&gt;m_wndToolBar;
                        (CMainFrame *)GetParent()-&gt;m_wndStatusBar;
                        </pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A8 name=A8></a> 8) 在Mainframe获得菜单指针
                        <pre>CMenu *pMenu=m_pMainWnd-&gt;GetMenu();</pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A9 name=A9></a> 9) 在任何类中获得应用程序类<br>用MFC全局函数AfxGetApp()获得。<br><br><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A10 name=A10></a> 10) 从文档类取得视图类的指针<br>我是从<a href="http://download.cqcnc.com/soft/program/article/vc/vc405.html" target=_blank><u><font color=#0000ff>http://download.cqcnc.com/soft/program/article/vc/vc405.html</font></u></a>学到的，从文档获得视图类指针目的一般为了控制同一文档的多个视图的定位问题，我的体会特别是文字处理CEditView当产生多个视图类时，这个功能是非常需要的。 <br>CDocument类提供了两个函数用于视图类的定位：<br>GetFirstViewPosition()和GetNextView()
                        <pre>virtual POSITION GetFirstViewPosition() const;
                        virtual CView* GetNextView(POSITION&amp; rPosition) const;<br>
                        </pre>
                        注意：GetNextView()括号中的参数用的是引用方式，因此执行后值可能改变。<br>GetFirstViewPosition()用于返回第一个视图位置（返回的并非视图类指针，而是一个POSITION类型值），GetNextView()有两个功能：返回下一个视图类的指针以及用引用调用的方式来改变传入的POSITION类型参数的值。很明显，在Test程序中，只有一个视图类，因此只需将这两个函数调用一次即可得到CTestView的指针如下（需定义一个POSITION结构变量来辅助操作）：
                        <pre>CTestView* pTestView;
                        POSITION pos=GetFirstViewPosition();
                        pTestView=GetNextView(pos);
                        </pre>
                        这样，便可到了CTestView类的指针pTestView.执行完几句后，变量pos=NULL,因为没有下一个视图类，自然也没有下一个视图类的POSITION.但是这几条语句太简单，不具有太强的通用性和安全特征；当象前面说的那样，当要在多个视图为中返回某个指定类的指针时，我们需要遍历所有视图类，直到找到指定类为止。判断一个类指针指向的是否某个类的实例时，可用IsKindOf()成员函数时行检查，如：
                        <pre>pView-&gt;IsKindOf(RUNTIME_CLASS(CTestView));</pre>
                        即可检查pView所指是否是CTestView类。<br><br>有了以上基础，我们已经可以从文档类取得任何类的指针。为了方便，我们将其作为一个文档类的成员函数，它有一个参数，表示要获得哪个类的指针。实现如下：
                        <pre>CView* CTestDoc::GetView(CRuntimeClass* pClass)
                        {
                        CView* pView;
                        POSITION pos=GetFirstViewPosition();
                        while(pos!=NULL){
                        pView=GetNextView(pos);
                        if(!pView-&gt;IsKindOf(pClass))
                        break;
                        }
                        if(!pView-&gt;IsKindOf(pClass)){
                        AfxMessageBox("Connt Locate the View.\r\n http://www.VCKBASE.com");
                        return NULL;
                        }
                        return pView;
                        }</pre>
                        <br>其中用了两次视图类的成员函数IsKindOf()来判断，是因为退出while循环有三种可能：<br><br>1.pos为NULL，即已经不存在下一个视图类供操作；<br>2.pView已符合要求。<br><br>1和2同是满足。这是因为GetNextView()的功能是将当前视图指针改变成一个视图的位置同时返回当前视图指针，因此pos是pView的下一个视图类的POSITION,完全有可能既是pos==NULL又是pView符合需要。当所需的视图是最后一个视图是最后一个视图类时就如引。因此需采用两次判断。<br>使用该函数应遵循如下格式（以取得CTestView指针为例）：
                        <pre>CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));</pre>
                        RUNTIME_CLASS是一个宏，可以简单地理解它的作用：将类的名字转化为CRuntimeClass为指针。<br>至于强制类型转换也是为了安全特性考虑的，因为从同一个基类之间的指针类型是互相兼容的。这种强制类型转换也许并不必要，但能避免一些可能出现的麻烦。<br><br>3.从一个视图类取得另一视图类的指针 综合1和2，很容易得出视图类之间互相获得指针的方法：就是用文档类作中转，先用1的方法得到文档类的指针，再用2的方法，以文档类的视图定位函数取得另一个视图类。同样，可以实现成一个函数：<br>（假设要从CTestAView中取得指向其它视图类的指针）
                        <pre>CView* CTestAView::GetView(CRuntimeClass* pClass)
                        {
                        CTestDoc* pDoc=(CTestDoc*)GetDocument();
                        CView* pView;
                        POSITION pos=pDoc-&gt;GetFirstViewPosition();
                        while(pos!=NULL){
                        pView=pDoc-&gt;GetNextView(pos);
                        if(!pView-&gt;IsKindOf(pClass))
                        break;
                        }
                        if(!pView-&gt;IsKindOf(pClass)){
                        AfxMessageBox("Connt Locate the View.");
                        return NULL;
                        }
                        return pView;
                        }</pre>
                        这个函数和2中的GetView()相比，一是多了第一句以取得文档类指针，二是在GetFirstViewPosition()和GetNextView()前加上了文档类指针，以表示它们是文档类成员函数。<br>有了此函数；当要从CTestAView中取得CTestBView的指针时，只需如下：
                        <pre>CTestBView* pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));</pre>
                        <img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A11 name=A11></a> 11）对于单文档中也可以加入多个文档模板，但是一般的开发就使用MDI方式开发多文档模板，其方法与上述视图的获取方法很接近，这里稍做解释，如果不清楚，请查阅MSDN，（以下四个内容（11、12、13、14）来源：<a href="http://sanjianxia.myrice.com/vc/vc45.htm" target=_blank><u><font color=#0000ff>http://sanjianxia.myrice.com/vc/vc45.htm</font></u></a>）<br><br>可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板的位置；<br>利用该值来调用CWinApp::GetNextDocTemplate函数，获得第一个CDocTemplate对象指针。
                        <pre>POSITION GetFirstDocTemplate( ) const;
                        CDocTemplate *GetNextDocTemplate( POSITION &amp; pos ) const;
                        </pre>
                        第二个函数返回由pos 标识的文档模板。POSITION是MFC定义的一个用于迭代或对象指针检索的值。通过这两个函数，应用程序可以遍历整个文档模板列表。如果被检索的文档模板是模板列表中的最后一个，则pos参数被置为NULL。<br><br><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A12 name=A12></a> 12）一个文档模板可以有多个文档，每个文档模板都保留并维护了一个所有对应文档的指针列表。 <br>用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一个文档的位置，并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与模板相关的文档列表。函数原形为：
                        <pre>viaual POSITION GetFirstDocPosition( ) const = 0;
                        visual CDocument *GetNextDoc(POSITION &amp; rPos) const = 0;
                        </pre>
                        如果列表为空，则rPos被置为NULL. <br><br><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A13 name=A13></a> 13）在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。函数原形如下：
                        <pre>CDocTemplate * GetDocTemplate ( ) const; </pre>
                        如果该文档不属于文档模板管理，则返回值为NULL。 <br><br><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A14 name=A14></a> 14)一个文档可以有多个视。每一个文档都保留并维护一个所有相关视的列表。CDocument::AddView将一个视连接到文档上，将该视加入到文档相联系的视的列表中，并将视的文档指针指向该文档。当有File/New、File/Open、Windows/New或Window/Split的命令而将一个新创建的视的对象连接到文档上时， MFC会自动调用该函数，框架通过文档/视的结构将文档和视联系起来。当然，程序员也可以根据自己的需要调用该函数。
                        <pre>Virtual POSITION GetFirstViewPosition( ) const;
                        Virtual CView * GetNextView( POSITION &amp;rPosition) cosnt;
                        </pre>
                        应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视的列表中的第一个视的位置，并调用CDocument::GetNextView返回指定位置的视，并将rPositon的值置为列表中下一个视的POSITION值。如果找到的视为列表中的最后一个视，则将rPosition置为NULL. <br><br><img height=16 src="http://www.vckbase.com/document/image/paragraph.gif" width=14><a id=A15 name=A15></a> 15)从一个视图类取得另一视图类的指针<br>这个应用在多视的应用程序中很多见，一般如果自己在主程序或者主框架中做好变量记号，也可以获得，还有比较通用的就是用文档类作中转，以文档类的视图遍历定位，取得另一个视图类。这个功能从本文第10项中可以得到。<br><br>这些资料大部分都是从网上和MSDN中获得的，写这个文档就是为了让大家不用再寻找，列出标题，可操作性更强。<br></td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/QUIRE-0216/aggbug/32198.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/QUIRE-0216/" target="_blank">QUIRE-0216</a> 2007-09-14 09:58 <a href="http://www.cppblog.com/QUIRE-0216/archive/2007/09/14/32198.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>透明位图的显示我的代码实现</title><link>http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31218.html</link><dc:creator>QUIRE-0216</dc:creator><author>QUIRE-0216</author><pubDate>Thu, 30 Aug 2007 09:05:00 GMT</pubDate><guid>http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31218.html</guid><wfw:comment>http://www.cppblog.com/QUIRE-0216/comments/31218.html</wfw:comment><comments>http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31218.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/QUIRE-0216/comments/commentRss/31218.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/QUIRE-0216/services/trackbacks/31218.html</trackback:ping><description><![CDATA[<p><strong>void TransparentBlt(CDC *pDestDC, int nXDest, int nYDest, int nWidth, int nHeight, CBitmap * pBitmap, int nXsrc, int nYsrc, COLORREF clr)<br>{<br>&nbsp;CDC maskDC, ImageDC;<br>&nbsp;maskDC.CreateCompatibleDC(pDestDC);<br>&nbsp;ImageDC.CreateCompatibleDC(pDestDC);</strong></p>
<p><strong>&nbsp;CBitmap maskBMP;<br>&nbsp;maskBMP.CreateBitmap(nWidth, nHeight, 1, 1, NULL);//创建单色掩码位图<br>&nbsp;CBitmap *pOldBMP = ImageDC.SelectObject(pBitmap);<br>&nbsp;CBitmap *maskOldBMP = maskDC.SelectObject(&amp;maskBMP);<br>&nbsp;<br>&nbsp;ImageDC.SetBkColor(clr);// 设置透明色<br>&nbsp;maskDC.BitBlt(0, 0, nWidth, nHeight, &amp;ImageDC, nXsrc, nYsrc, SRCCOPY);</strong></p>
<p><strong>&nbsp;//设置背景色为黑色，前景色为白色，将掩码位图与原位图相"与"<br>&nbsp;ImageDC.SetBkColor(RGB(0, 0, 0));<br>&nbsp;ImageDC.SetTextColor(RGB(255, 255, 255));<br>&nbsp;ImageDC.BitBlt(0, 0, nWidth, nHeight, &amp;maskDC, nXsrc, nYsrc, SRCAND);</strong></p>
<p><strong>&nbsp;//设置背景色为白色，前景色为黑色，将掩码位图与背景进行&#8220;与&#8221;运算<br>&nbsp;pDestDC-&gt;SetBkColor(RGB(255, 255, 255));<br>&nbsp;pDestDC-&gt;SetTextColor(RGB(0, 0, 0));<br>&nbsp;pDestDC-&gt;BitBlt(nXDest, nYDest, nWidth, nHeight, &amp;maskDC, nXsrc, nYsrc, SRCAND);<br>&nbsp;// "或"运算,生成最终效果<br>&nbsp;pDestDC-&gt;BitBlt(nXDest, nYDest, nWidth, nHeight, &amp;ImageDC, nXsrc, nYsrc, SRCPAINT);</strong></p>
<p><strong>&nbsp;if (pOldBMP) ImageDC.SelectObject(pOldBMP);<br>&nbsp;ImageDC.DeleteDC();<br>&nbsp;if (maskOldBMP) maskDC.SelectObject(maskOldBMP);<br>&nbsp;maskDC.DeleteDC();<br>&nbsp;if (maskBMP.m_hObject) maskBMP.DeleteObject();<br>}</strong></p>
我就不怎么解释了!如不理解,请看我转的(<strong>透明位图的显示中的(二、实现TransparentBlt函数)的原理</strong>),其他部分都就什么必要了!呵呵!
<img src ="http://www.cppblog.com/QUIRE-0216/aggbug/31218.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/QUIRE-0216/" target="_blank">QUIRE-0216</a> 2007-08-30 17:05 <a href="http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31218.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>透明位图的显示(转)</title><link>http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31212.html</link><dc:creator>QUIRE-0216</dc:creator><author>QUIRE-0216</author><pubDate>Thu, 30 Aug 2007 08:52:00 GMT</pubDate><guid>http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31212.html</guid><wfw:comment>http://www.cppblog.com/QUIRE-0216/comments/31212.html</wfw:comment><comments>http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31212.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/QUIRE-0216/comments/commentRss/31212.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/QUIRE-0216/services/trackbacks/31212.html</trackback:ping><description><![CDATA[<p>包含透明色的位图的绘制方法有多种，最简单的方法是调用现成的函数：TransparentBlt,也可以通过自己的代码实现类似 TransparentBlt的功能，实现过程也有两种形式，一种是事先做一张掩码位图，另一种是动态生成掩码位图。本文将介绍动态生成掩码位图绘制具有透明区域位图的方法。<br><br><strong>一、TransparentBlt 函数的使用 </strong><br><br>TransparentBlt 函数在Windows98/Windows2000以上版本运行，系统中需要包含 Msimg32.dll，使用时可以链接 Msimg32.lib。<br>Windows98下的TransparentBlt会产生资源泄漏，所以不建议在WIN98下使用该函数。<br>TransparentBlt函数原型如下: </p>
<pre>BOOL TransparentBlt(
HDC hdcDest,      // 目标DC
int nXOriginDest,   // 目标X偏移
int nYOriginDest,   // 目标Y偏移
int nWidthDest,     // 目标宽度
int hHeightDest,    // 目标高度
HDC hdcSrc,         // 源DC
int nXOriginSrc,    // 源X起点
int nYOriginSrc,    // 源Y起点
int nWidthSrc,      // 源宽度
int nHeightSrc,     // 源高度
UINT crTransparent  // 透明色,COLORREF类型
);
</pre>
使用示例:
<pre>CBitmap FootballBMP;
FootballBMP.LoadBitmap(IDB_FOOTBALLBMP);
CDC ImageDC;
ImageDC.CreateCompatibleDC(pDC);
CBitmap *pOldImageBMP = ImageDC.SelectObject(&amp;FootballBMP);
TransparentBlt(pDC-&gt;m_hDC, 0, 0, 218, 199, ImageDC.m_hDC, 0, 0, 218, 199, RGB(0,0,0xff));
ImageDC.SelectObject(pOldImageBMP);
</pre>
<strong>二、实现TransparentBlt函数</strong><br><br>为了理解具有透明色位图的绘制过程，我们来亲手建立一个具有同TransparentBlt功能一致的实验函数，称之为TransparentBlt2。<br><br>实验素材：有两张位图：bk.bmp是背景位图，football.bmp包含透明区域，透明色为蓝色RGB(0,0,0xff)<br>实验目的：以bk.bmp为背景，将football.bmp绘制到背景中，形成如下的最终效果图。<br><img height=164 src="http://www.vckbase.com/document/journal/vckbase18/images/transBlt1.gif" width=542>
<p>&#160;</p>
<br><br><strong>2.1 透明位图绘制原理</strong><br>假设football.bmp -&gt;载入 HBITMAP hImageBMP -&gt; 选入 HDC hImageDC<br><br><strong>2.1.1 生成足球的单色掩码位图，透明区域为白色（全1），非透明区域为黑色（全0)</strong>
<pre>HBITMAP hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 建立单色位图
SetBkColor(hImageDC, RGB(0,0,0xff)); // 设置背景色为蓝色
BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY); // 拷贝到hMaskDC</pre>
这样足球位图中蓝色区域在掩码位图中成了白色，其它区域为黑色，此时hMaskBMP 如下图:<br><img height=85 src="http://www.vckbase.com/document/journal/vckbase18/images/transBlt2.gif" width=93 border=1> (图一)<br><br><strong>2.1.2 设置背景色为黑色，前景色为白色，将掩码位图(图一)与足球位图相"与"</strong>
<pre>SetBkColor(hImageDC, RGB(0,0,0));
SetTextColor(hImageDC, RGB(255,255,255));
BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);
</pre>
这样，掩码位图中背景色（黑色）的区域在hImageBMP中被保留，前景色（白色）的部分变为黑色。 此时hImageBMP 如下图:<br><img height=85 src="http://www.vckbase.com/document/journal/vckbase18/images/transBlt3.gif" width=94> (图二)<br><br><strong>2.1.3 设置背景色为白色，前景色为黑色，将掩码位图(图一)与背景进行&#8220;与&#8221;运算</strong><br>
<pre>SetBkColor(hdcDest,RGB(255,255,255));
SetTextColor(hdcDest,RGB(0,0,0));
BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);</pre>
掩码中白色区域（数据与1相&#8220;与&#8221;结果不变）使背景保持不变，黑色区域变成黑色，此时背景显示如下:<br><img height=105 src="http://www.vckbase.com/document/journal/vckbase18/images/transBlt4.gif" width=144> (图三)<br><br><strong>2.1.4 将hImageBMP(图二)与背景(图三)进行&#8220;或&#8221;运算</strong>
<pre>BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCPAINT);</pre>
这样就将足球绘制到背景上了。<br><br><strong>2.2 TransparentBlt2函数全部实现代码</strong><br>
<pre>void TransparentBlt2( HDC hdcDest,      // 目标DC
int nXOriginDest,   // 目标X偏移
int nYOriginDest,   // 目标Y偏移
int nWidthDest,     // 目标宽度
int nHeightDest,    // 目标高度
HDC hdcSrc,         // 源DC
int nXOriginSrc,    // 源X起点
int nYOriginSrc,    // 源Y起点
int nWidthSrc,      // 源宽度
int nHeightSrc,     // 源高度
UINT crTransparent  // 透明色,COLORREF类型
)
{
HBITMAP hOldImageBMP, hImageBMP = CreateCompatibleBitmap(hdcDest, nWidthDest, nHeightDest);	// 创建兼容位图
HBITMAP hOldMaskBMP, hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL);			// 创建单色掩码位图
HDC		hImageDC = CreateCompatibleDC(hdcDest);
HDC		hMaskDC = CreateCompatibleDC(hdcDest);
hOldImageBMP = (HBITMAP)SelectObject(hImageDC, hImageBMP);
hOldMaskBMP = (HBITMAP)SelectObject(hMaskDC, hMaskBMP);
// 将源DC中的位图拷贝到临时DC中
if (nWidthDest == nWidthSrc &amp;&amp; nHeightDest == nHeightSrc)
BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
else
StretchBlt(hImageDC, 0, 0, nWidthDest, nHeightDest,
hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, SRCCOPY);
// 设置透明色
SetBkColor(hImageDC, crTransparent);
// 生成透明区域为白色，其它区域为黑色的掩码位图
BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY);
// 生成透明区域为黑色，其它区域保持不变的位图
SetBkColor(hImageDC, RGB(0,0,0));
SetTextColor(hImageDC, RGB(255,255,255));
BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);
// 透明部分保持屏幕不变，其它部分变成黑色
SetBkColor(hdcDest,RGB(255,255,255));
SetTextColor(hdcDest,RGB(0,0,0));
BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);
// "或"运算,生成最终效果
BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCPAINT);
// 清理、恢复
SelectObject(hImageDC, hOldImageBMP);
DeleteDC(hImageDC);
SelectObject(hMaskDC, hOldMaskBMP);
DeleteDC(hMaskDC);
DeleteObject(hImageBMP);
DeleteObject(hMaskBMP);
}</pre>
<strong>2.3 TransparentBlt的另外一个版本:TransparentBltU</strong><br><br>TransparentBltU是Christian Graus 在WinDEV发表的一个函数，功能与TransparentBlt一致，以下是全部实现代码:
<pre>bool TransparentBltU(
HDC dcDest,         // handle to Dest DC
int nXOriginDest,   // x-coord of destination upper-left corner
int nYOriginDest,   // y-coord of destination upper-left corner
int nWidthDest,     // width of destination rectangle
int nHeightDest,    // height of destination rectangle
HDC dcSrc,          // handle to source DC
int nXOriginSrc,    // x-coord of source upper-left corner
int nYOriginSrc,    // y-coord of source upper-left corner
int nWidthSrc,      // width of source rectangle
int nHeightSrc,     // height of source rectangle
UINT crTransparent  // color to make transparent
)
{
if (nWidthDest &lt; 1) return false;
if (nWidthSrc &lt; 1) return false;
if (nHeightDest &lt; 1) return false;
if (nHeightSrc &lt; 1) return false;
HDC dc = CreateCompatibleDC(NULL);
HBITMAP bitmap = CreateBitmap(nWidthSrc, nHeightSrc, 1, GetDeviceCaps(dc,
BITSPIXEL), NULL);
if (bitmap == NULL)
{
DeleteDC(dc);
return false;
}
HBITMAP oldBitmap = (HBITMAP)SelectObject(dc, bitmap);
if (!BitBlt(dc, 0, 0, nWidthSrc, nHeightSrc, dcSrc, nXOriginSrc,
nYOriginSrc, SRCCOPY))
{
SelectObject(dc, oldBitmap);
DeleteObject(bitmap);
DeleteDC(dc);
return false;
}
HDC maskDC = CreateCompatibleDC(NULL);
HBITMAP maskBitmap = CreateBitmap(nWidthSrc, nHeightSrc, 1, 1, NULL);
if (maskBitmap == NULL)
{
SelectObject(dc, oldBitmap);
DeleteObject(bitmap);
DeleteDC(dc);
DeleteDC(maskDC);
return false;
}
HBITMAP oldMask =  (HBITMAP)SelectObject(maskDC, maskBitmap);
SetBkColor(maskDC, RGB(0,0,0));
SetTextColor(maskDC, RGB(255,255,255));
if (!BitBlt(maskDC, 0,0,nWidthSrc,nHeightSrc,NULL,0,0,BLACKNESS))
{
SelectObject(maskDC, oldMask);
DeleteObject(maskBitmap);
DeleteDC(maskDC);
SelectObject(dc, oldBitmap);
DeleteObject(bitmap);
DeleteDC(dc);
return false;
}
SetBkColor(dc, crTransparent);
BitBlt(maskDC, 0,0,nWidthSrc,nHeightSrc,dc,0,0,SRCINVERT);
SetBkColor(dc, RGB(0,0,0));
SetTextColor(dc, RGB(255,255,255));
BitBlt(dc, 0,0,nWidthSrc,nHeightSrc,maskDC,0,0,SRCAND);
HDC newMaskDC = CreateCompatibleDC(NULL);
HBITMAP newMask;
newMask = CreateBitmap(nWidthDest, nHeightDest, 1,
GetDeviceCaps(newMaskDC, BITSPIXEL), NULL);
if (newMask == NULL)
{
SelectObject(dc, oldBitmap);
DeleteDC(dc);
SelectObject(maskDC, oldMask);
DeleteDC(maskDC);
DeleteDC(newMaskDC);
DeleteObject(bitmap);
DeleteObject(maskBitmap);
return false;
}
SetStretchBltMode(newMaskDC, COLORONCOLOR);
HBITMAP oldNewMask = (HBITMAP) SelectObject(newMaskDC, newMask);
StretchBlt(newMaskDC, 0, 0, nWidthDest, nHeightDest, maskDC, 0, 0,
nWidthSrc, nHeightSrc, SRCCOPY);
SelectObject(maskDC, oldMask);
DeleteDC(maskDC);
DeleteObject(maskBitmap);
HDC newImageDC = CreateCompatibleDC(NULL);
HBITMAP newImage = CreateBitmap(nWidthDest, nHeightDest, 1,
GetDeviceCaps(newMaskDC, BITSPIXEL), NULL);
if (newImage == NULL)
{
SelectObject(dc, oldBitmap);
DeleteDC(dc);
DeleteDC(newMaskDC);
DeleteObject(bitmap);
return false;
}
HBITMAP oldNewImage = (HBITMAP)SelectObject(newImageDC, newImage);
StretchBlt(newImageDC, 0, 0, nWidthDest, nHeightDest, dc, 0, 0, nWidthSrc,
nHeightSrc, SRCCOPY);
SelectObject(dc, oldBitmap);
DeleteDC(dc);
DeleteObject(bitmap);
BitBlt( dcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
newMaskDC, 0, 0, SRCAND);
BitBlt( dcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
newImageDC, 0, 0, SRCPAINT);
SelectObject(newImageDC, oldNewImage);
DeleteDC(newImageDC);
SelectObject(newMaskDC, oldNewMask);
DeleteDC(newMaskDC);
DeleteObject(newImage);
DeleteObject(newMask);
return true;
}</pre>
<br>说明：本文提供的TransparentBlt2函数旨在说明透明位图的显示原理，在Windows2000以上环境实际运用中建议使用现成的TransparentBlt函数来绘制透明位图。
<img src ="http://www.cppblog.com/QUIRE-0216/aggbug/31212.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/QUIRE-0216/" target="_blank">QUIRE-0216</a> 2007-08-30 16:52 <a href="http://www.cppblog.com/QUIRE-0216/archive/2007/08/30/31212.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>                                                    用对话框创建CDialogBar派生的类</title><link>http://www.cppblog.com/QUIRE-0216/archive/2007/08/24/30771.html</link><dc:creator>QUIRE-0216</dc:creator><author>QUIRE-0216</author><pubDate>Fri, 24 Aug 2007 09:17:00 GMT</pubDate><guid>http://www.cppblog.com/QUIRE-0216/archive/2007/08/24/30771.html</guid><wfw:comment>http://www.cppblog.com/QUIRE-0216/comments/30771.html</wfw:comment><comments>http://www.cppblog.com/QUIRE-0216/archive/2007/08/24/30771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/QUIRE-0216/comments/commentRss/30771.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/QUIRE-0216/services/trackbacks/30771.html</trackback:ping><description><![CDATA[&nbsp;
<p align=left><span>&nbsp;&nbsp;一、</span><span>创建</span><span>DialogBar</span><span>的派生类</span></p>
<p align=left><span>首先，创建对话框资源：在对话框资源编辑器内生成一个</span><span>Dialog</span><span>资源，并将其风格（</span><span>Style</span><span>）属性必须设置为</span><span>Child</span><span>，不能设置为</span><span>Overlapped</span><span>或</span><span>Popup</span><span>，否则运行肯定出错；至于边界属性则随用户自己喜欢，一般都是选择</span><span>None</span><span>。其余属性也随用户选择，一般没有特殊要求还是选择默认的好。</span></p>
<p align=left><span>其次，创建基于</span><span>CDialog</span><span>的派生类：打开</span><span>ClassWizard</span><span>，为以上创建的资源添加一个以</span><span>CDialog</span><span>为基类的派生类（因为</span><span>ClassWizard</span><span>没有将</span><span>CDialogBar</span><span>列在基类目录清单中，所以用户只能先以</span><span>CDialog</span><span>类派生）。</span></p>
<p align=left><span>再次，修改派生类以</span><span>CDialogBar</span><span>为基类：通常需要手工修改几处代码，在本例中派生类以</span><span>CDataStatus</span><span>命名。（注：以后讲解中凡是手工改动都是以灰背景显示）</span></p>
<p align=left><span>1</span><span>、</span>&nbsp;<span>在头文件中修改继承关系</span></p>
<p align=left><span>将</span><span>class CDataStatus : public CDialog&nbsp;</span><span>改为</span><strong><span>class CDataStatus : public CDialogBar</span></strong></p>
<p align=left><span>2</span><span>、</span>&nbsp;<span>在代码文件中修该构造函数继承关系</span></p>
<p align=left><span>将</span><span>CDataStatus::CDataStatus(CWnd* pParent /*=NULL*/)</span></p>
<p align=left><span>: CDialog(CDataStatus::IDD, pParent)</span></p>
<p align=left><span>{</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>//{{AFX_DATA_INIT(CDataStatus)</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// NOTE: the ClassWizard will add member initialization here</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>//}}AFX_DATA_INIT</span></p>
<p align=left><span>}</span></p>
<p align=left><span>改为</span></p>
<p align=left><strong><span>CDataStatus::CDataStatus(CWnd* pParent /*=NULL*/) </span></strong></p>
<p align=left><strong><span>{ </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp; </span>//{{AFX_DATA_INIT(CDataStatus) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>// NOTE: the ClassWizard will add member initialization here </span></span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp; </span>//}}AFX_DATA_INIT </span></strong></p>
<p align=left><strong><span>}</span></strong><strong><span> </span></strong></p>
<p align=left><span>3</span><span>、</span>&nbsp;<span>将</span><span>DDX</span><span>绑定函数中的继承关系去掉</span></p>
<p align=left><span>即将</span><span>void CDataStatus::DoDataExchange(CDataExchange* pDX)</span></p>
<p align=left><span>{</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>CDialog::DoDataExchange(pDX);</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>//{{AFX_DATA_MAP(CCurrentCheckDlg)</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>&#8230;&#8230;&#8230;..</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span>//}}AFX_DATA_MAP</span></p>
<p align=left><span>}</span></p>
<p align=left><span>改为</span></p>
<p align=left><strong><span>void CDataStatus::DoDataExchange(CDataExchange* pDX) </span></strong></p>
<p align=left><strong><span>{ </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp; </span>//{{AFX_DATA_MAP(CCurrentCheckDlg) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp; </span>&#8230;&#8230;&#8230;&#8230;. </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp; </span>//}}AFX_DATA_MAP </span></strong></p>
<p align=left><strong><span>}</span></strong><strong><span> </span></strong></p>
<p align=left><span>4</span><span>、</span>&nbsp;<span>重新初始化函数（这个相当重要，如果不这么做的话，</span><span>DDX</span><span>函数形同虚设，当然用户的工具条如果没有用到</span><span>DDX</span><span>的话当然可以不加这段代码）：</span></p>
<p align=left><span>首先在</span><span>ClassWizard</span><span>的</span><span>MessageMap</span><span>中对消息该</span><span>CDataStatus</span><span>类的</span><span>WM_INITDIALOG</span><span>消息添加处理函数默认名为</span><span>OnInitDialog</span><span>。</span></p>
<p align=left><span>其次手工修改代码如下：</span></p>
<p align=left><span>1</span><span>、</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>添加消息映射函数。由于对话框形式的初始化函数消息并未加载到消息映射内，为此我们需要手工添加，要不然代码无法拦截该工具条的初始化消息，形式如下：</span></p>
<p align=left><span>将</span><span>BEGIN_MESSAGE_MAP(CDataStatus, CDialogBar)</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//{{AFX_MSG_MAP(CDataStatus)</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>.......</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//}}AFX_MSG_MAP</span></p>
<p align=left><span>END_MESSAGE_MAP()</span></p>
<p align=left><span>改为：</span></p>
<p align=left><strong><span>BEGIN_MESSAGE_MAP(CDataStatus, CDialogBar) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//{{AFX_MSG_MAP(CDataStatus) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>....... </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>ON_MESSAGE(WM_INITDIALOG,OnInitDialog) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//}}AFX_MSG_MAP </span></strong></p>
<p align=left><strong><span>END_MESSAGE_MAP()</span></strong><strong><span> </span></strong></p>
<p align=left><span>2</span><span>、</span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>修改</span><span>OnInitDialog</span><span>函数，此函数并未传递参数，但是在这里我们需要让它传递参数，代码如下修改（当然头文件中，对声明也要做修改，在这里就不作赘述了）</span></p>
<p align=left><span>将</span><span>BOOL CDataStatus::OnInitDialog() </span></p>
<p align=left><span>{</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>CDialogBar::OnInitDialog();</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp; </span></span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// TODO: Add extra initialization here</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return TRUE;&nbsp;// return TRUE unless you set the focus to a control</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// EXCEPTION: OCX Property Pages should return FALSE</span></p>
<p align=left><span>}</span></p>
<p align=left><span>改为：</span></p>
<p align=left><strong><span>BOOL CDataStatus::OnInitDialog(UINT wParam,LONG lParam) </span></strong></p>
<p align=left><strong><span>{ </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>//CDialogBar::OnInitDialog(); </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;</span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// TODO: Add extra initialization here </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>BOOL bRet = HandleInitDialog(wParam,lParam); </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if (!UpdateData(FALSE)) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{ </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>TRACE("InitCDataStatus Failed</span></strong><strong><span>！</span></strong><strong><span>"); </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>} </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return TRUE;&nbsp;// return TRUE unless you set the focus to a control </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// EXCEPTION: OCX Property Pages should return FALSE </span></strong></p>
<p align=left><strong><span>}</span></strong><strong><span> </span></strong></p>
<p align=left>&nbsp;</p>
<p align=left><span>二、</span><span>在框架类中实现该派生类的对象化</span></p>
<p align=left><span>首先，在框架类的头文件内声明实例对象，本例实例化：</span><strong><span>CDataStatus<span>&nbsp;&nbsp;&nbsp; </span>m_wndDataStatus;</span></strong><span>当然头文件中不可避免要包含新派生类的头文件。</span></p>
<p align=left><span>其次，在框架类的</span><span>OnCreate</span><span>函数内创建对象并将对象绑定对话框资源。形式与创建</span><span>ToolBar</span><span>原理一样，本例实例如下：</span></p>
<p align=left><strong><span>if (!m_wndDataStatus.Create(this,IDD_DATASTATUS,WS_VISIBLE|WS_CHILD </span></strong></p>
<p align=left><strong><span>|CBRS_SIZE_DYNAMIC|CBRS_BOTTOM,IDD_DATASTATUS)) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{ </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>TRACE0("Failed to create CDataStatus bar!"); </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return -1; </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></strong><strong><span> </span></strong></p>
<p align=left><span>再次，最为关键的一点就是重写框架类的</span><span>OnCmdMsg</span><span>虚函数。如果不重写该函数，那么不光</span><span>DDX</span><span>功能无法实现，连最基本的</span><span>OnCommand</span><span>事件都无法实现。而且还得手工添加代码，形式如下：</span></p>
<p align=left><span>BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, </span></p>
<p align=left><span>AFX_CMDHANDLERINFO* pHandlerInfo) </span></p>
<p align=left><span>{</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// TODO: Add your specialized code here and/or call the base class</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);</span></p>
<p align=left><span>}</span></p>
<p align=left><span>改为：</span></p>
<p align=left><strong><span>BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) </span></strong></p>
<p align=left><strong><span>{ </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>// TODO: Add your specialized code here and/or call the base class </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>if (m_wndDataStatus.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo)) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return<span>&nbsp;&nbsp;&nbsp; </span>TRUE; </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); </span></strong></p>
<p align=left><strong><span>}</span></strong><strong><span> </span></strong></p>
<p align=left><span>三、</span><span>在</span><span>CReBar</span><span>上添加该实例化对象</span></p>
<p align=left><span>其实这一步倒是相当简单，只是自己以前没用过这个类，所以在这里也顺便用了一下。</span></p>
<p align=left><span>首先，在框架类的头文件中用</span><span>CRebar</span><span>声明一个对象，如</span><strong><span>CReBar<span>&nbsp;&nbsp; </span>m_wndReBar;</span></strong></p>
<p align=left><span>其次，在框架类的代码文件中的</span><span>OnCreat</span><span>函数体内，生成对象，代码如下：</span></p>
<p align=left><strong><span>if (!m_wndReBar.Create(this,RBS_BANDBORDERS,WS_CHILD | </span></strong></p>
<p align=left><strong><span>WS_VISIBLE| CBRS_BOTTOM|WS_CLIPSIBLINGS|WS_CLIPCHILDREN)) </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{ </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>TRACE0("Failed to create&nbsp;Rebar \n"); </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>return -1; </span></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}</span></strong><strong><span> </span></strong></p>
<p align=left><span>再次，就是将所要添加的</span><span>toolbar</span><span>以及新生成的</span><span>CDataStatus</span><span>对象</span><span>m_wndDataStatus</span><span>加进</span><span>Rebar</span><span>的对象</span><span>m_wndReBar</span><span>中，代码如下：</span></p>
<p align=left><strong><span>m_wndReBar.AddBar(&amp;m_wndDataStatus,NULL,NULL, </span></strong></p>
<p align=left><strong><span>RBBS_GRIPPERALWAYS|RBBS_FIXEDBMP);</span></strong><strong><span> </span></strong></p>
<img src ="http://www.cppblog.com/QUIRE-0216/aggbug/30771.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/QUIRE-0216/" target="_blank">QUIRE-0216</a> 2007-08-24 17:17 <a href="http://www.cppblog.com/QUIRE-0216/archive/2007/08/24/30771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>