Click here to Skip to main content
12,944,738 members (49,724 online)
Click here to Skip to main content
Add your own
alternative version


47 bookmarked
Posted 25 Jan 2010

Selection Rectangle: An Implementation in "Explorer style" :)

, 28 Jan 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
A semi-transparent selection rectangle



I could not find a complete replacement for the old API function DrawFocusRect(...) to use it in my views...

So I did it my way. Now it's here, for your response too.


A layered window could play the role of such selection rectangle in an excellent manner - because of its possibility to be shown with the alpha blending. In this case, we don't need to control the repainting of the client area of the parent view of selection (it would be necessary when we would draw something dynamically changeable in its dimensions in the device context of the parent view).

I have written a class CCoverWnd : public CWnd to implement the behaviour of the selection rectangle. This window must be semi-transparent now layered in its job.

Step 1. Creating of a Layered Window

We have to set a special extension window style WS_EX_LAYERED at creation of a layered window. In addition, we must remember that a layered window may not be a child. Since the selection rectangle has no title bar, we can specify the normal window style as WS_POPUP:

bool CCoverWnd::Create(CWnd* pParentView)
  bool bResult = false;

  if (pParentView) {
    // The special style of the layered windows (WS_EX_LAYERED) will be used:

    CreateEx(WS_EX_LAYERED,                          // to be created as a layered window

             _T("STATIC"),                           // using of an existing window class

             NULL,                                   // there is no title 

                                                     // for the rectangle

             WS_POPUP | WS_VISIBLE,                  // common window styles

             -1, -1, 0, 0,                           // initial position and dimensions

             pParentView->GetSafeHwnd(),             // parent view of the rectangle

             NULL);                                  // not used menu identifier

    if (GetSafeHwnd()) {
      pParentView->GetClientRect(m_cParentCliRect);  // client area of the parent view

      pParentView->ClientToScreen(m_cParentCliRect); // our coordinates 

                                                     // are screen related

      pParentView->SetFocus();                       // return the focus at parent

      bResult = true;

  return bResult;

Now we can create our covering window and need a possibility to show it at some position, in some size and with some painted surface... :)

Step 2. Updating of a Layered Window

There is an API function to update the placement and the content of a layered window (WinUser.h):

    __in HWND hWnd,                  // handle of the layered window

    __in_opt HDC hdcDst,             // destination DC (in our case screen DC)

    __in_opt POINT *pptDst,          // destination position at the screen

    __in_opt SIZE *psize,            // dimensions of window at the screen

    __in_opt HDC hdcSrc,             // source (memory) DC of prepainting

    __in_opt POINT *pptSrc,          // source position for the surface bits transfer

    __in COLORREF crKey,             // color to be fully transparent (not our case)

    __in_opt BLENDFUNCTION *pblend,  // blending parameters

    __in DWORD dwFlags);             // kind of the transfer 

                                     // (in our case ULW_ALPHA - for alpha blending)

The parameter pblend is a pointer of type struct BLENDFUNCTION that is described below (WinGDI.h):

typedef struct _BLENDFUNCTION
    BYTE   BlendOp;                  // must be AC_SRC_OVER currently

    BYTE   BlendFlags;               // must be zero

    BYTE   SourceConstantAlpha;      // general surface transparency 

                                     // [0(opaque) -255(transparent)]

    BYTE   AlphaFormat;              // 0 - the transparency of the surface bits 

                                     // has no role

                                     // AC_SRC_ALPHA - the transparency of the 

                                     // surface bits has a role

                                     // this parameter is independent from 

                                     // SourceConstantAlpha


Implementation of the Updating

Now we can provide our own function for CCoverWnd to show it :).

// Placing the window at the screen position crPos

void CCoverWnd::ShowAt(const CRect& crPos)
  if (GetSafeHwnd()) {
    CRect cMoveRect(crPos);

    CRect cIntersectRect(cMoveRect);
    cIntersectRect.IntersectRect(m_cDrawRect, cMoveRect); // allowed area for placing

    int iWidth(cMoveRect.Width());   // painting dimension per X

    int iHeight(cMoveRect.Height()); // painting dimension per Y

    HDC hdcScreen = ::GetDC(NULL);           // destination screen DC

    HDC hDC = ::CreateCompatibleDC(hdcScreen); // source memory DC

    // We have to create a bitmap by CreateDIBSection(..)

    // to operate with its bits directly. Thanks to SledgeHammer01

    BITMAPINFO sBI              = {0};
    sBI.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    sBI.bmiHeader.biWidth       = iWidth; 
    sBI.bmiHeader.biHeight      = iHeight; 
    sBI.bmiHeader.biPlanes      = 1; 
    sBI.bmiHeader.biBitCount    = 32; 
    sBI.bmiHeader.biCompression = BI_RGB;

    HBITMAP hBmp = ::CreateDIBSection(hDC, &sBI, DIB_RGB_COLORS, NULL, NULL, 0);
    HBITMAP hBmpOld = (HBITMAP) ::SelectObject(hDC, hBmp);
    bool bFillAlphaOK = FillAlpha(hBmp); // try to fill the surface bits 

                                         // with alpha channel

    if (!bFillAlphaOK) {
      FillRGB(hDC, iWidth, iHeight); // else - without the alpha channel


    // Preparing the blend parameters

    BLENDFUNCTION blend       = {0};
    blend.BlendOp             = AC_SRC_OVER;
    blend.SourceConstantAlpha = bFillAlphaOK ? 160 : 64;
    blend.AlphaFormat         = bFillAlphaOK ? AC_SRC_ALPHA : 0;

    // Destination position at the screen

    POINT ptPos   = {cIntersectRect.left,

    // Dimensions of the bits transfer

    SIZE sizeWnd  = {cIntersectRect.Width(),

    // Source position in source (memory DC)

    POINT ptSrc   = {cIntersectRect.left - cMoveRect.left,

    // Call the wizard :)

    ::UpdateLayeredWindow(m_hWnd, hdcScreen, &ptPos, &sizeWnd,
                          hDC, &ptSrc, 0, &blend, ULW_ALPHA);

    // Clearance

    ::SelectObject(hDC, hBmpOld);
    ::ReleaseDC(NULL, hdcScreen);

The fill-out procedures are encapsulated in CCoverWnd and could be observed in the source files (the third download set above).

Using of Code

It would be enough to instance and create an object of the CCoverWnd class in a CWnd-inherited object, that should provide the selection on its surface.

class CCoverTestDlg : public CDialog
  bool      m_bCaptured;
  CPoint    m_cpStart,

  CCoverWnd m_cCoverWnd; // An own test instance, could be static :)


Now it would be possible to show the cover, for example:

void CCoverTestDlg::ShowCover()
  if (!m_cCoverWnd.GetSafeHwnd()) {
    m_cCoverWnd.Create(this); // The info of the client area will be used

                              // by the child-cover, see CCoverWnd::Create(..)


  if (m_cCoverWnd.GetSafeHwnd()) {
    CRect cShowRect(m_cpStart, m_cpEnd);
    ClientToScreen(cShowRect); // The cover is screen related

    m_cCoverWnd.ShowAt(cShowRect); // Good luck...


... as well to "hide" it:

void CCoverTestDlg::DestroyCover()
  if (m_cCoverWnd.GetSafeHwnd()) {
    m_cCoverWnd.DestroyWindow(); // Thanks...


Points of Interest

Thanks to SledgeHammer01 - for the advice to write the color data directly, without the function CBitmap::SetBitmapBits(..).

The touched function has the following state now:

bool CCoverWnd::FillAlpha(HBITMAP hBmp)
  bool bResult = false;

  if (hBmp) {
    BITMAP bmp;
    GetObject(hBmp, sizeof(BITMAP), &bmp);

    DWORD dwCount = bmp.bmWidthBytes * bmp.bmHeight;
    if (dwCount >= sizeof(DWORD)) {
      DWORD* pcBitsWords = (DWORD*) bmp.bmBits;
      if (pcBitsWords) {
        DWORD dwIndex(dwCount / sizeof(DWORD));
        DWORD dwUp = bmp.bmWidth;
        DWORD dwDn = dwIndex -dwUp;
        DWORD dwR  = bmp.bmWidth -1;
        while (dwIndex--)  {
          DWORD dwSides = dwIndex % bmp.bmWidth;
          if (dwIndex < dwUp ||
              dwIndex > dwDn ||
              0   == dwSides ||
              dwR == dwSides) {
            pcBitsWords[dwIndex] = sm_clrPenA;   // 0xFF0080FF (Edge, AA =0xFF)

          } else {
            pcBitsWords[dwIndex] = sm_clrBrushA; // 0x400020FF (Plain, AA =0x40)

        bResult = true;

  return bResult;

I would be glad to read the next advice to improve the bits writing.

Thank you!


  • Mon Jan 25 12:46:50 UTC+0100 2010 -- Created
  • Mon Jan 25 17:48:01 UTC+0100 2010 -- Modified section "Background"
  • Mon Jan 25 18:01:36 UTC+0100 2010 -- Modified section "Points of Interest"
  • Thu Jan 28 12:13:54 UTC+0100 2010 -- Improved code


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Eugen Podsypalnikov
Software Developer COPA-DATA GmbH
Austria Austria
No Biography provided

You may also be interested in...

Comments and Discussions

Question.NET Pin
Ger8315-Aug-12 0:33
memberGer8315-Aug-12 0:33 
AnswerRe: .NET Pin
Eugen Podsypalnikov15-Aug-12 2:58
memberEugen Podsypalnikov15-Aug-12 2:58 
GeneralSuggestion Pin
Junlin Xu6-Jan-11 7:23
memberJunlin Xu6-Jan-11 7:23 
GeneralFillAlpha() optimizations... Pin
SledgeHammer0126-Jan-10 11:22
memberSledgeHammer0126-Jan-10 11:22 
GeneralRe: FillAlpha() optimizations... Pin
Eugen Podsypalnikov26-Jan-10 19:38
memberEugen Podsypalnikov26-Jan-10 19:38 
GeneralRe: FillAlpha() optimizations... Pin
SledgeHammer0126-Jan-10 20:09
memberSledgeHammer0126-Jan-10 20:09 
GeneralRe: FillAlpha() optimizations... Pin
Eugen Podsypalnikov26-Jan-10 23:22
memberEugen Podsypalnikov26-Jan-10 23:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170518.1 | Last Updated 28 Jan 2010
Article Copyright 2010 by Eugen Podsypalnikov
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid