• [转]一些简单常用的功能函数 - [技术资料]

    2009-02-15

    分类: 技术资料

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://laybor.blogbus.com/logs/35201963.html

    1.    如何激活当前屏幕保护程序
    // 激活当前屏幕保护程序, jingzhou xu
        PostMessage(WM_SYSCOMMAND,SC_SCREENSAVE,0);

    2.    如何禁止/启用屏幕保护及电源管理
    static UINT dss_GetList[] = {SPI_GETLOWPOWERTIMEOUT, SPI_GETPOWEROFFTIMEOUT, SPI_GETSCREENSAVETIMEOUT};

    static UINT dss_SetList[] = {SPI_SETLOWPOWERTIMEOUT, SPI_SETPOWEROFFTIMEOUT, SPI_SETSCREENSAVETIMEOUT};

    static const int dss_ListCount = _countof(dss_GetList);
    l    禁止屏幕保护及电源管理
    {
    m_pValue = new int[dss_ListCount];
    for (int x=0;x<dss_ListCount;x++)
    {
    // 禁止屏幕保护及电源管理
    VERIFY(SystemParametersInfo (dss_SetList[x], 0, NULL, 0));
    }
    delete[] m_pValue;
    }

    l    启用屏幕保护及电源管理
    {
    m_pValue = new int[dss_ListCount];
    for (int x=0;x<dss_ListCount;x++)
    {
    //启用屏幕保护及电源管理
    VERIFY(SystemParametersInfo (dss_SetList[x], m_pValue[x], NULL, 0));
    }
    delete[] m_pValue;
    }

    3.    如何激活和关闭IE浏览器
    //激活并打开IE
    void lounchIE()
    {
      HWND h=FindWindowEx(NULL,NULL,NULL,
                          "Microsoft Internet Explorer") ;
      ShellExecute(h,"open","C:\\simple.html",
                   NULL,NULL,SW_SHOWNORMAL);

    }

    //关闭IE及其它应用
    void CloseIE()
    {
      int app=BSM_APPLICATIONS;
      unsigned long  bsm_app=(unsigned long )app;
      BroadcastSystemMessage(BSF_POSTMESSAGE,&bsm_app,
                             WM_CLOSE,NULL,NULL);
    }

    4.    如何给树控件加入工具提示
    l    首先给树控件加入TVS_INFOTIP属性风格,如下所示:
    if (!m_ctrlTree.Create(WS_CHILD|WS_VISIBLE|
        TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT|TVS_SHOWSELALWAYS|TVS_INFOTIP, //加入提示TVS_INFOTIP,jingzhou xu(树控件ID:100)
            CRect(0, 0, 0, 0), &m_wndTreeBar, 100))
        {
            TRACE0("Failed to create instant bar child\n");
            return -1;
        }
    l    其次加入映射消息声明,如下所示:
    afx_msg void OnGetInfoTip(NMHDR* pNMHDR,LRESULT* pResult);       //树控件上加入提示消息,jingzhou xu   

    ON_NOTIFY(TVN_GETINFOTIP, 100, OnGetInfoTip)                  //树控件条目上加入提示,jingzhou xu
    l    最后加入呼应涵数处理:
    void CCreateTreeDlg::OnGetInfoTip(NMHDR* pNMHDR,
                                        LRESULT* pResult)
      {
      *pResult = 0;
      NMTVGETINFOTIP* pTVTipInfo = (NMTVGETINFOTIP*)pNMHDR;
      LPARAM itemData = (DWORD) pTVTipInfo->lParam;
      //对应每个条目的数据
      HTREEITEM hItem = pTVTipInfo->hItem;
      CString tip;
      HTREEITEM hRootItem = m_chassisTree.GetRootItem();
      if (hRootItem != pTVTipInfo->hItem)
      {
        tip = "树结点的提示";
      }
      else
      {
        tip = "树根上的提示";
      }
      strcpy(pTVTipInfo->pszText, (LPCTSTR) tip);
    }

    5.    如何获取系统信息框的路径
    #include <atlbase.h>

    #define IDS_REG_KEY_MSINFO_PATH1 _T( "Software\\Microsoft\\Shared Tools\\MSInfo" )
    #define IDS_REG_KEY_MSINFO_PATH2 _T( "Software\\Microsoft\\Shared Tools Location" )
    #define IDS_REG_VAL_MSINFO_PATH1 _T( "Path" )
    #define IDS_REG_VAL_MSINFO_PATH2 _T( "MSInfo" )
    #define IDS_MSINFO_EXE_NAME      _T( "MSInfo32.exe" )

    //...

    BOOL GetSysInfoPath( CString& strPath )
    {       
        strPath.Empty();
        LPTSTR  pszPath = strPath.GetBuffer( MAX_PATH );
           
        CRegKey reg;
        DWORD   dwSize  = MAX_PATH;
        LONG    nRet    = reg.Open( HKEY_LOCAL_MACHINE, IDS_REG_KEY_MSINFO_PATH1, KEY_READ );
                   
        // 在注册表中寻找第一个"MSInfo32.exe" 位置
        if ( nRet == ERROR_SUCCESS )
        {
            #if ( _MFC_VER >= 0x0700 )
                nRet = reg.QueryStringValue( IDS_REG_VAL_MSINFO_PATH1, pszPath, &dwSize );
            #else
                nRet = reg.QueryValue( pszPath, IDS_REG_VAL_MSINFO_PATH1, &dwSize );
            #endif

            reg.Close();
        }
       
        // 如果第一次寻找失败,则进行第二次寻找
        if ( nRet != ERROR_SUCCESS )
        {
            nRet = reg.Open( HKEY_LOCAL_MACHINE, IDS_REG_KEY_MSINFO_PATH2, KEY_READ );

            if ( nRet == ERROR_SUCCESS )
            {
                #if ( _MFC_VER >= 0x0700 )
                    reg.QueryStringValue( IDS_REG_VAL_MSINFO_PATH2, pszPath, &dwSize );
                #else
                    reg.QueryValue( pszPath, IDS_REG_VAL_MSINFO_PATH2, &dwSize );
                #endif
               
                // 路径名不包括EXE文件名
                if ( nRet == ERROR_SUCCESS )
                    VERIFY( ::PathAppend( pszPath, IDS_MSINFO_EXE_NAME ) );

                reg.Close();
            }
        }
           
        strPath.ReleaseBuffer();
        strPath.FreeExtra();
       
        // 检查文件是否有效.   
        return ::PathFileExists( strPath );
    }

    6.    如何直接运行一个资源中的程序
    bool Run()
       {
        CFile f;
        char* pFileName = "Execution.exe";
        if( !f.Open( pFileName, CFile::modeCreate | CFile::modeWrite, NULL ) )
        {
            AfxMessageBox("Can not create file!");
            return 0;
        }
            CString path = f.GetFilePath();
        HGLOBAL hRes;
        HRSRC hResInfo;
         //获取应用实例 
        HINSTANCE insApp = AfxGetInstanceHandle();
         //寻找EXE资源名
        hResInfo = FindResource(insApp,(LPCSTR)IDR_EXE4,"EXE");
        hRes = LoadResource(insApp,hResInfo );   // Load it
        DWORD dFileLength = SizeofResource( insApp, hResInfo );  //计算EXE文件大小
        f.WriteHuge((LPSTR)hRes,dFileLength);  //写入临时文件
        f.Close();
        HINSTANCE HINSsd = ShellExecute(NULL, "open",path, NULL, NULL, SW_SHOWNORMAL);> //运行它. 
        return 1;
    }

    7.    如何遍历整个目录
    #include <windows.h>
    #include <shlobj.h>

    //浏览目录.
    void    BrowseFolder( void )
    {
        TCHAR path[MAX_PATH];
        BROWSEINFO bi = { 0 };
        bi.lpszTitle = ("递归调用所有目录");
        LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );
       
        if ( pidl != 0 )
        {
            // 获取目录路径
            SHGetPathFromIDList ( pidl, path );

            //设置为当前路径
            SetCurrentDirectory ( path );
       
            //搜索所有子目录
            SearchFolder( path );


            // 释放内存
            IMalloc * imalloc = 0;
            if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
            {
                imalloc->Free ( pidl );
                imalloc->Release ( );
            }
    }


    //搜索其下所有子目录及文件.
    void    SearchFolder( TCHAR * path )
    {
            WIN32_FIND_DATA FindFileData;
            HANDLE            hFind;

            TCHAR    filename[ MAX_PATH + 256 ];
            TCHAR    pathbak[ MAX_PATH ];

            //复制初始用户选择目录
            strcpy( pathbak, path );

            //寻找第一个文件
            hFind = FindFirstFile ( "*.*", &FindFileData );

            //搜索所有文件及子目录
            do
            {
                if ( hFind != INVALID_HANDLE_VALUE )
                {
                    //如果是当前目录或父目录,跳过
                    if ( ! ( strcmp( FindFileData.cFileName, "." ) ) || ! ( strcmp( FindFileData.cFileName, ".." ) ) )
                    {
                        continue;
                    }

                    //恢复初始用户选择目录
                    strcpy( path, pathbak );

                    //列出所有发现的文件
                    sprintf( path, "%s\\%s", path, FindFileData.cFileName );

                    //如果 SetCurrentDirectory 成功的话,则它是一个目录,递归调用继续搜索子目录
                    if ( ( SetCurrentDirectory( path ) ) )
                    {
                        SearchFolder( path );
                    }
                   
                      //插入文件及路径名到列表框m_listbox_hwnd中
                       SendMessage( m_listbox_hwnd, LB_ADDSTRING, 0, path ); //<--INSERT WHAT YOU WANT DONE HERE!
                }
            }
            while ( FindNextFile ( hFind, &FindFileData ) && hFind != INVALID_HANDLE_VALUE );

            FindClose ( hFind );
    }

    8.    如何禁止/启用系统热键
    bool bOld;
    l    禁止系统热键
    //屏蔽掉系统键
    SystemParametersInfo(SPI_SETSCREENSAVERRUNNING,true,&bOld,SPIF_UPDATEINIFILE);

    l    启用系统热键
    //恢复系统热键   
    SystemParametersInfo(SPI_SETSCREENSAVERRUNNING,false,&bOld,SPIF_UPDATEINIFILE);

    9.    如何隐藏/显示WINDOWS系统任务栏
    l    隐藏系统任务栏
    //隐藏WINDOWS系统任务栏
        ::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_HIDE);
    l    显示系统任务栏
    //恢复WINDOWS系统任务栏正常显示
    ::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_SHOW);

    10.    如何实现窗口到系统区图标间的动画效果
    //********************************************************************************
    //* 名称:FindTrayWnd
    //* 作者:徐景周(jingzhou_xu@163.net)
    //* 功能:在显示窗体动画效果前,先寻找系统区位置
    //********************************************************************************
        BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam)
    {
        TCHAR szClassName[256];
        GetClassName(hwnd, szClassName, 255);

        // 比较窗口类名
        if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0)
        {
            CRect *pRect = (CRect*) lParam;
            ::GetWindowRect(hwnd, pRect);
            return TRUE;
        }

        // 当找到时钟窗口时表示可以结束了
        if (_tcscmp(szClassName, _T("TrayClockWClass")) == 0)
        {
            CRect *pRect = (CRect*) lParam;
            CRect rectClock;
            ::GetWindowRect(hwnd, rectClock);
            pRect->right = rectClock.left;
            return FALSE;
        }

        return TRUE;
    }

    //********************************************************************************
    //* 名称:WinAnimation
    //* 作者:徐景周(jingzhou_xu@163.net)
    //* 功能:显示窗口动画效果的涵数
    //********************************************************************************
    void CScreenSnapDlg::WinAnimation(BOOL ShowFlag)
    {
        CRect rect(0,0,0,0);

        // 查找托盘窗口
        CWnd* pWnd = FindWindow("Shell_TrayWnd", NULL);
        if (pWnd)
        {
            pWnd->GetWindowRect(rect);
            EnumChildWindows(pWnd->m_hWnd, FindTrayWnd, (LPARAM)&rect);
            //rect 为托盘区矩形
            CRect rcWnd;
            GetWindowRect(rcWnd);
            if(ShowFlag)                    //窗体滑向系统区
              DrawAnimatedRects(GetSafeHwnd(),IDANI_CAPTION,rcWnd,rect);
            else                            //窗体从系统区滑出
              DrawAnimatedRects(GetSafeHwnd(),IDANI_CAPTION,rect,rcWnd);
        }
    }

    用法如下:
    if(IsWindowVisible())                 //窗体是否已隐藏
    {
        ShowWindow(SW_HIDE);           //先隐藏窗体
        WinAnimation(true);                 //窗体动画滑入到系统区中
    }
    else
    {
    WinAnimation(false);         //窗体动画从系统区滑出
        ShowWindow(SW_SHOW);
    }

    11.    如何判断当前操作系统的版本
    //------------------------------------------------------------------------------------------------
    //判断操作系统涵数及变量,jingzhou xu
    typedef enum tagWin32SysType{
        Windows32s,
        WindowsNT3,
        Windows95,
        Windows98,
        WindowsME,
        WindowsNT4,
        Windows2000,
        WindowsXP
    }Win32SysType;

    //判断操作系统涵数及变量,jingzhou xu
    Win32SysType IsShellSysType()
    {
        Win32SysType  ShellType;
        DWORD winVer;
        OSVERSIONINFO *osvi;
       
        winVer=GetVersion();
        if(winVer<0x80000000){/*NT */
            ShellType=WindowsNT3;
            osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
            if (osvi!=NULL){
                memset(osvi,0,sizeof(OSVERSIONINFO));
                osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
                GetVersionEx(osvi);
                if(osvi->dwMajorVersion==4L)ShellType=WindowsNT4;
                else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==0L)ShellType=Windows2000;
                else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==1L)ShellType=WindowsXP;
                free(osvi);
            }
        }
        else if  (LOBYTE(LOWORD(winVer))<4)
            ShellType=Windows32s;
        else{
            ShellType=Windows95;
            osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
            if (osvi!=NULL){
                memset(osvi,0,sizeof(OSVERSIONINFO));
                osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
                GetVersionEx(osvi);
                if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==10L)ShellType=Windows98;
                else if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==90L)ShellType=WindowsME;
                free(osvi);
            }
        }

        return ShellType;
    }
    //------------------------------------------------------------------------------------------------

    12.    如何在指定矩形框内水平/垂直显示多行文字
    ///////////////////////////////////////////////////////
    //说明:
    //  在矩形框中水平或垂直显示多行文字,jingzhou xu.
    //  lMode: 排列方式,0:水平方式; 1:垂直对齐   
    //  lHori: 水平对齐方式, 0:左对齐; 1:居中; 2:右对齐; 3:自定义
    //  lVert: 垂直对齐方式, 0:顶对齐; 1:居中; 2:底对齐; 3:自定义
    ///////////////////////////////////////////////////////
    CRect DrawTitleInRect(CDC *pDC, CString szString, LPRECT lpRect, long lMode, long lHori, long lVert)
    {
        TEXTMETRIC tm;
        pDC->GetTextMetrics(&tm);
        int tmpWidth=tm.tmAveCharWidth, tmpHeight=tm.tmHeight;

        CRect rcInner(lpRect);
        if(lMode==0)
        {
            rcInner.left+=tmpWidth;
            rcInner.right-=tmpWidth;
            rcInner.top-=tmpWidth;
            rcInner.bottom+=tmpWidth;
        }
        if(lMode==1)
        {
            rcInner.left+=tmpWidth;
            rcInner.right=rcInner.left+tmpWidth;
            rcInner.top-=tmpWidth;
            rcInner.bottom+=tmpWidth;
        }

        pDC->DrawText(szString, rcInner,DT_CALCRECT);

        switch(lHori)
        {
        case 0:
            break;
        case 1:
            {
                long xOutCent=(lpRect->right+lpRect->left)/2;
                long xInnCent=(rcInner.right+rcInner.left)/2;
                rcInner.left+=(xOutCent-xInnCent);
                rcInner.right+=(xOutCent-xInnCent);
            }
            break;
        case 2:
            {
                long lInWidth=rcInner.right-rcInner.left;
                rcInner.right=lpRect->right-tmpWidth;
                rcInner.left=rcInner.right-lInWidth;
            }
            break;
        default:
            break;
        }
       
        switch(lVert)
        {
        case 0:
            break;
        case 1:
            {
                long yOutCent=(lpRect->bottom+lpRect->top)/2;
                long yInnCent=(rcInner.bottom+rcInner.top)/2;
                rcInner.top-=(yInnCent-yOutCent);
                rcInner.bottom-=(yInnCent-yOutCent);
            }
            break;
        case 2:
            {
                long lInHeigh=rcInner.top-rcInner.bottom;
                rcInner.bottom=lpRect->bottom+tmpWidth;
                rcInner.top=rcInner.bottom+lInHeigh;
            }
            break;
        default:
            break;
        }

        //---------------------------------------------------------------------------------------------
        //功能:根据新、老矩形,重新计算行数,使文字多行显示,jingzhou xu
        //---------------------------------------------------------------------------------------------
        //一行中最大字符数
        int nMaxLineChar = abs(lpRect->right - lpRect->left) / tmpWidth ;       
        //记录当前行的宽度
        short theLineLength=0;
        //记录当前行中汉字字节数,以防止将一半汉字分为两行
        unsigned short halfChinese=0;

        for(int i=0; i<=szString.GetLength()-1; i++)
        {
            if(((unsigned char)szString.GetAt(i) == 0x0d) && ((unsigned char)szString.GetAt(i+1) == 0x0a))
                theLineLength=0;

            //大于0xa1的字节为汉字字节
            if((unsigned char)szString.GetAt(i) >= 0xA1)
                halfChinese++;
            theLineLength++;

            //如果行宽大于每行最大宽度,进行特殊处理
            if(theLineLength > nMaxLineChar)
            {
                //防止将一个汉字分为两行,回溯
                if(halfChinese%2)
                {
                    szString.Insert(i,(unsigned char)0x0a);
                    szString.Insert(i,(unsigned char)0x0d);
                }
                else
                {
                    szString.Insert(i-1,(unsigned char)0x0a);
                    szString.Insert(i-1,(unsigned char)0x0d);
                }
               
                theLineLength = 0;
            }
        }

        //重新计算矩形边界范围
    //    int tmpLine = int(abs(szString.GetLength()*tmpWidth / abs(lpRect->right - lpRect->left)-0.5));
    //    tmpLine += (szString.GetLength()*tmpWidth % abs(lpRect->right - lpRect->left))? 1 : 0;
    //    if(tmpLine == 0)
    //        tmpLine = 1;
        if(rcInner.bottom > lpRect->bottom)
            rcInner.bottom = lpRect->bottom;
        if(rcInner.top < lpRect->top)
            rcInner.top = lpRect->top;

        //---------------------------------------------------------------------------------------------

        if(lHori==0)
            pDC->DrawText(szString, rcInner, DT_WORDBREAK|DT_LEFT);
        else if(lHori==1)
            pDC->DrawText(szString, rcInner, DT_WORDBREAK|DT_CENTER);
        else if(lHori==2)
            pDC->DrawText(szString, rcInner, DT_WORDBREAK|DT_RIGHT);

        return rcInner;
    }

    13.    如何在指定矩形中旋转显示文字
    ///////////////////////////////////////////////////////
    //说明:
    //  在矩形框中旋转方式显示文字,jingzhou xu
    //参数:    
    //  pDC:        DC指针
    //  str:        显示文字
    //  rect:        显示范围
    //  angle:        旋转角度
    //    nOptions:    ExtTextOut()中相应设置<ETO_CLIPPED 和 ETO_OPAQUE>
    ///////////////////////////////////////////////////////
    void DrawRotatedText(CDC* pDC, const CString str, CRect rect,
                         double angle, UINT nOptions)
    {
       //按比例转换角度值
       double pi = 3.141592654;
       double radian = pi * 2 / 360 * angle;

       //获取显示文字中心点
       CSize TextSize = pDC->GetTextExtent(str);
       CPoint center;
       center.x = TextSize.cx / 2;
       center.y = TextSize.cy / 2;

       //计算显示文字新的中心点
       CPoint rcenter;
       rcenter.x = long(cos(radian) * center.x - sin(radian) * center.y);
       rcenter.y = long(sin(radian) * center.x + cos(radian) * center.y);

       //绘制文字
       pDC->SetTextAlign(TA_BASELINE);
       pDC->SetBkMode(TRANSPARENT);
       pDC->ExtTextOut(rect.left + rect.Width() / 2 - rcenter.x,
                       rect.top + rect.Height() / 2 + rcenter.y,
                       nOptions, rect, str, NULL);
    }

    14.    如何将32 x 32像素图标转换为16 x 16像素值的图标
    HICON Convert32x32IconTo16x16(HICON h32x32Icon)
    {
      HDC hMainDC, hMemDC1, hMemDC2;
      HICON h16x16Icon;
      BITMAP bmp;
      HBITMAP hOldBmp1, hOldBmp2;
      ICONINFO IconInfo32x32, IconInfo16x16;

      GetIconInfo(h32x32Icon, &IconInfo32x32);

      hMainDC = ::GetDC(m_hWnd);
      hMemDC1 = CreateCompatibleDC(hMainDC);
      hMemDC2 = CreateCompatibleDC(hMainDC);

      GetObject(IconInfo32x32.hbmColor, sizeof(BITMAP), &bmp);

      IconInfo16x16.hbmColor = CreateBitmap( 16, 16,
                                             bmp.bmPlanes,
                                             bmp.bmBitsPixel,
                                             NULL);

      hOldBmp1 = (HBITMAP) SelectObject( hMemDC1,
                                         IconInfo32x32.hbmColor);
      hOldBmp2 = (HBITMAP) SelectObject( hMemDC2,
                                         IconInfo16x16.hbmColor);

      StretchBlt(hMemDC2,
           0, 0,
           16, 16,
           hMemDC1,
           0, 0,
           32, 32,
           SRCCOPY
           );

      GetObject(IconInfo32x32.hbmMask, sizeof(BITMAP), &bmp);

      IconInfo16x16.hbmMask = CreateBitmap( 16, 16,
                                            bmp.bmPlanes,
                                            bmp.bmBitsPixel,
                                            NULL);

      SelectObject(hMemDC1, IconInfo32x32.hbmMask);
      SelectObject(hMemDC2, IconInfo16x16.hbmMask);

      StretchBlt(hMemDC2,
                 0, 0,
                 16, 16,
                 hMemDC1,
                 0, 0,
                 32, 32,
                 SRCCOPY
           );

      SelectObject(hMemDC1, hOldBmp1);
      SelectObject(hMemDC2, hOldBmp2);

      IconInfo16x16.fIcon = TRUE;
      h16x16Icon = CreateIconIndirect(&IconInfo16x16);

      DeleteObject(IconInfo32x32.hbmColor);
      DeleteObject(IconInfo16x16.hbmColor);
      DeleteObject(IconInfo32x32.hbmMask);
      DeleteObject(IconInfo16x16.hbmMask);
      DeleteDC(hMemDC1);
      DeleteDC(hMemDC2);
      ::ReleaseDC(m_hWnd, hMainDC);

      return h16x16Icon;
    }

    15.    如何建立一个灰度级图标
    HICON CreateGrayscaleIcon(HICON hIcon)
    {
      HICON       hGrayIcon = NULL;
      HDC         hMainDC = NULL,
                  hMemDC1 = NULL,
                  hMemDC2 = NULL;
      BITMAP      bmp;
      HBITMAP     hOldBmp1 = NULL,
                  hOldBmp2 = NULL;
      ICONINFO    csII, csGrayII;
      BOOL        bRetValue = FALSE;

      bRetValue = ::GetIconInfo(hIcon, &csII);
      if (bRetValue == FALSE) return NULL;

      hMainDC = ::GetDC(m_hWnd);
      hMemDC1 = ::CreateCompatibleDC(hMainDC);
      hMemDC2 = ::CreateCompatibleDC(hMainDC);
      if (hMainDC == NULL ||
        hMemDC1 == NULL ||
        hMemDC2 == NULL)
          return NULL;

      if (::GetObject(csII.hbmColor,
                    sizeof(BITMAP), &
                    amp;bmp))
      {
        csGrayII.hbmColor =
             ::CreateBitmap(csII.xHotspot*2,
                            csII.yHotspot*2,
                            bmp.bmPlanes,
                            bmp.bmBitsPixel,
                            NULL);
        if (csGrayII.hbmColor)
        {
          hOldBmp1 =
             (HBITMAP)::SelectObject(hMemDC1,
                                     csII.hbmColor);
          hOldBmp2 =
             (HBITMAP)::SelectObject(hMemDC2,
                                     csGrayII.hbmColor);

          ::BitBlt(hMemDC2, 0, 0, csII.xHotspot*2,
                   csII.yHotspot*2, hMemDC1, 0, 0,
                   SRCCOPY);

          DWORD    dwLoopY = 0, dwLoopX = 0;
          COLORREF crPixel = 0;
          BYTE     byNewPixel = 0;

          for (dwLoopY = 0; dwLoopY < csII.yHotspot*2; dwLoopY++)
          {
            for (dwLoopX = 0; dwLoopX < csII.xHotspot*2; dwLoopX++)
            {
              crPixel = ::GetPixel(hMemDC2, dwLoopX, dwLoopY);

              byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) +
                   (GetGValue(crPixel) * 0.587) +
                   (GetBValue(crPixel) * 0.114));
              if (crPixel) ::SetPixel(hMemDC2,
                                      dwLoopX,
                                      dwLoopY,
                                      RGB(byNewPixel,
                                      byNewPixel,
                                      byNewPixel));
            } // for
          } // for

          ::SelectObject(hMemDC1, hOldBmp1);
          ::SelectObject(hMemDC2, hOldBmp2);

          csGrayII.hbmMask = csII.hbmMask;

          csGrayII.fIcon = TRUE;
          hGrayIcon = ::CreateIconIndirect(&csGrayII);
        } // if

        ::DeleteObject(csGrayII.hbmColor);
        //::DeleteObject(csGrayII.hbmMask);
      } // if

      ::DeleteObject(csII.hbmColor);
      ::DeleteObject(csII.hbmMask);
      ::DeleteDC(hMemDC1);
      ::DeleteDC(hMemDC2);
      ::ReleaseDC(m_hWnd, hMainDC);

      return hGrayIcon;
    }

    16.    如何按指定角度旋转显示内存位图(用法和BitBlt类似)
    void RotBlt(HDC destDC, int srcx1, int srcy1, int srcx2, int srcy2,
      HDC srcDC , int destx1, int desty1 ,int thetaInDegrees ,DWORD mode)
    {
      double theta = thetaInDegrees * (3.14159/180);

      //原图像原始大小
      int width = srcx2 - srcx1;
      int height = srcy2 - srcy1;

      //原图像中心点
      int centreX = int(float(srcx2 + srcx1)/2);
      int centreY = int(float(srcy2 + srcy1)/2);

      //判断出图像可以沿任意方向旋转的矩形框
      if(width>height)height = width;
      else
        width = height;


      HDC memDC = CreateCompatibleDC(destDC);
      HBITMAP memBmp = CreateCompatibleBitmap(destDC, width, height);

      HBITMAP obmp = (HBITMAP) SelectObject(memDC, memBmp);

      //内存DC新在中心点
      int newCentre = int(float(width)/2);

      //开始旋转
      for(int x = srcx1; x<=srcx2; x++)
        for(int y = srcy1; y<=srcy2; y++)
        {
          COLORREF col = GetPixel(srcDC,x,y);

          int newX = int((x-centreX)*sin(theta)+(y-centreY)*cos(theta));
          int newY = int((x-centreX)*cos(theta)-(y-centreY)*sin(theta));


          SetPixel(memDC , newX + newCentre, newY + newCentre, col);
        }

      //复制到目标DC上
      BitBlt(destDC, destx1, desty1, width, height, memDC, 0,0,mode);


      //释放内存
      SelectObject(memDC, obmp);

      DeleteDC(memDC);
      DeleteObject(memBmp);
    }

    用法:
    RotBlt(dc, 0,0,150,150,memDC,200,0, 45, SRCCOPY);

    17.    如何将指定的窗体,以位图形式复制到系统剪切板上
    void CScreenSnapDlg::toClipboard_Bio(CWnd * wnd, BOOL FullWnd)
    {
         CDC *dc;
         if(FullWnd)
            { /* 抓取整个窗口 */
             dc = new CWindowDC(wnd);
            } /* 抓取整个窗口 */
         else
            { /* 仅抓取客户区时 */
             dc = new CClientDC(wnd);
            } /* 仅抓取客户区时 */

         CDC memDC;
         memDC.CreateCompatibleDC(dc);

         CBitmap bm;
         CRect r;
         if(FullWnd)
            wnd->GetWindowRect(&r);
         else
             wnd->GetClientRect(&r);

         CString s;
         wnd->GetWindowText(s);
         CSize sz(r.Width(), r.Height());
         bm.CreateCompatibleBitmap(dc, sz.cx, sz.cy);
         CBitmap * oldbm = memDC.SelectObject(&bm);
         memDC.BitBlt(0, 0, sz.cx, sz.cy, dc, 0, 0, SRCCOPY);

         //直接调用OpenClipboard(),而不用wnd->GetParent()->OpenClipboard();
         wnd->OpenClipboard();

         ::EmptyClipboard();
         ::SetClipboardData(CF_BITMAP, bm.m_hObject);
         CloseClipboard();

         //恢复原始环境
         memDC.SelectObject(oldbm);
         bm.Detach(); 

         delete dc;
    }

    18.    如何替换HBITMAP中的颜色值
    #define COLORREF2RGB(Color) (Color & 0xff00) | ((Color >> 16) & 0xff) \
                                                 | ((Color << 16) & 0xff0000)

    HBITMAP ReplaceColor (HBITMAP hBmp,COLORREF cOldColor,COLORREF cNewColor)
    {
        HBITMAP RetBmp=NULL;
        if (hBmp)
        {   
            HDC BufferDC=CreateCompatibleDC(NULL);        // 源位图DC
            if (BufferDC)
            {
                SelectObject(BufferDC,hBmp);         // 选入DC中
               
                HDC DirectDC=CreateCompatibleDC(NULL);      // 目标DC
                if (DirectDC)
                {
                    // 获取源位图大小
                    BITMAP bm;
                    GetObject(hBmp, sizeof(bm), &bm);
                   
                    // 初始化BITMAPINFO信息,以便使用CreateDIBSection
                    BITMAPINFO RGB32BitsBITMAPINFO;
                    ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO));
                    RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
                    RGB32BitsBITMAPINFO.bmiHeader.biWidth=bm.bmWidth;
                    RGB32BitsBITMAPINFO.bmiHeader.biHeight=bm.bmHeight;
                    RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1;
                    RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32;
                    UINT * ptPixels;   

                    HBITMAP DirectBitmap= CreateDIBSection(DirectDC,
                                                  (BITMAPINFO *)&RGB32BitsBITMAPINFO,
                                                  DIB_RGB_COLORS,(void **)&ptPixels, NULL, 0);
                    if (DirectBitmap)
                    {
                        HGDIOBJ PreviousObject=SelectObject(DirectDC, DirectBitmap);
                        BitBlt(DirectDC,0,0,bm.bmWidth,bm.bmHeight,BufferDC,0,0,SRCCOPY);

                        // 转换 COLORREF 为 RGB
                        cOldColor=COLORREF2RGB(cOldColor);
                        cNewColor=COLORREF2RGB(cNewColor);

                        // 替换颜色
                        for (int i=((bm.bmWidth*bm.bmHeight)-1);i>=0;i--)
                        {
                            if (ptPixels[i]==cOldColor) ptPixels[i]=cNewColor;
                        }
                       
                        // 修改位图 DirectBitmap
                        SelectObject(DirectDC,PreviousObject);
                       
                        // 完成
                        RetBmp=DirectBitmap;
                    }
                    // 释放DC
                    DeleteDC(DirectDC);
                }
                // 释放DC
                DeleteDC(BufferDC);
            }
        }
        return RetBmp;
    }

    用法:
    HBITMAP hBmp2 = LoadBitmap(g_hinstance,MAKEINTRESOURCE(IDB_SAMPLEBITMAP));
    HBITMAP hBmp = ReplaceColor(hBmp2,0xff0000,0x00ff00); // 替换蓝色为绿色

    ......

    DeleteObject(hBmp2);
    DeleteObject(hBmp);

    19.    如何转换并保存位图
    //********************************************************************************
    //* 名称:DDBToDIB
    //* 作者:徐景周(jingzhou_xu@163.net)
    //* 功能:设备相关转换为设备无关位图
    //********************************************************************************
    HANDLE CScreenSnapDlg::DDBToDIB( CBitmap& bitmap, DWORD dwCompression /* = BI_RGB */)
    {
        BITMAP                bm;
        BITMAPINFOHEADER    bi;
        LPBITMAPINFOHEADER  lpbi;
        DWORD                dwLen;
        HANDLE                hDIB;
        HANDLE                handle;
        HDC                    hDC;
        HPALETTE            hPal;

        CWindowDC            dc( this );
        CPalette            pal;
        //如果支持调色板的话,则建立它
        if( dc.GetDeviceCaps( RASTERCAPS ) & RC_PALETTE )
        {
            UINT        nSize   = sizeof(LOGPALETTE) + ( sizeof(PALETTEENTRY) * 256 );
            LOGPALETTE* pLP     = (LOGPALETTE*)new BYTE[nSize];
            pLP->palVersion     = 0x300;
            pLP->palNumEntries = (unsigned short)GetSystemPaletteEntries( dc, 0, 255,
            pLP->palPalEntry );

            pal.CreatePalette( pLP );

            //释放
            delete[] pLP;
        }

        ASSERT( bitmap.GetSafeHandle() );

        //不支持BI_BITFIELDS类型
        if( dwCompression == BI_BITFIELDS )
            return NULL;

        //如果调色板为空,则用默认调色板
        hPal = (HPALETTE) pal.GetSafeHandle();
        if (hPal==NULL)
            hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

        //获取位图信息
        bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

        //初始化位图信息头
        bi.biSize        = sizeof(BITMAPINFOHEADER);
        bi.biWidth        = bm.bmWidth;
        bi.biHeight         = bm.bmHeight;
        bi.biPlanes         = 1;
        bi.biBitCount        = (unsigned short)(bm.bmPlanes * bm.bmBitsPixel) ;
        bi.biCompression    = dwCompression;
        bi.biSizeImage        = 0;
        bi.biXPelsPerMeter    = 0;
        bi.biYPelsPerMeter    = 0;
        bi.biClrUsed        = 0;
        bi.biClrImportant    = 0;

        //计算信息头及颜色表大小
        int nColors = 0;
        if(bi.biBitCount <= 8)
            {
            nColors = (1 << bi.biBitCount);
            }
        dwLen  = bi.biSize + nColors * sizeof(RGBQUAD);

        hDC = ::GetDC(NULL);
        hPal = SelectPalette(hDC,hPal,FALSE);
        RealizePalette(hDC);

        //为信息头及颜色表分配内存
        hDIB = GlobalAlloc(GMEM_FIXED,dwLen);

        if (!hDIB){
            SelectPalette(hDC,hPal,FALSE);
            ::ReleaseDC(NULL,hDC);
            return NULL;
        }

        lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);

        *lpbi = bi;

        //调用 GetDIBits 计算图像大小
        GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight,
                (LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);

        bi = *lpbi;

        //图像的每一行都对齐(32bit)边界
        if (bi.biSizeImage == 0){
            bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
                            * bi.biHeight;

            if (dwCompression != BI_RGB)
                bi.biSizeImage = (bi.biSizeImage * 3) / 2;
        }

        //重新分配内存大小,以便放下所有数据
        dwLen += bi.biSizeImage;
        handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE) ;
        if (handle != NULL)
            hDIB = handle;
        else
            {
            GlobalFree(hDIB);

            //重选原始调色板
            SelectPalette(hDC,hPal,FALSE);
            ::ReleaseDC(NULL,hDC);
            return NULL;
            }

        //获取位图数据
        lpbi = (LPBITMAPINFOHEADER)hDIB;

        //最终获得的DIB
        BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),
                    0L,                      //扫描行起始处
                    (DWORD)bi.biHeight,      //扫描行数
                    (LPBYTE)lpbi             //位图数据地址
                    + (bi.biSize + nColors * sizeof(RGBQUAD)),
                    (LPBITMAPINFO)lpbi,      //位图信息地址
                    (DWORD)DIB_RGB_COLORS);  //颜色板使用RGB

        if( !bGotBits )
        {
            GlobalFree(hDIB);
    &nb


    历史上的今天: