   [Win32 C++] Change Control Windows Shape
  Hello, yes I am back again talking about making a Win32 Custom Control :P I am not going to let it beat me lol.Anyway, I have made success on creating my Custom Control/Window. But I want to make the control/window an elliptical shape, not rectangular. Can anyone suggest how I do this?I know how to make an Elliptical region & I know how to change the position of the window/control(SetWindowPos()) but is there a function or way to change the shape of my control to circular?Here is my attempt in the draw event, but it just makes a circular region INSIDE my rectangular control, I know this because even when I left click outside the circle the control still receives the WM_LBUTTONDOWN messageBelow is my Custom Controls' WndProc() ( not my Main WndProc() ):LRESULT CALLBACK CustomControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){   // Post: Receives all CustomControl window messages CustomControl *cc = (CustomControl*)GetWindowLong(hwnd,0); switch (msg)    {    case WM_NCCREATE:    {    cc = (CustomControl*)malloc(sizeof(CustomControl));   if (cc==false) {   MessageBox(NULL,"Failed to create CustomControl window","Error",MB_OK|MB_ICONERROR);   return 0;    }   SetWindowLong(hwnd,0,(LONG)cc); // Attach custom class to this window.    }    break;    case WM_PAINT:    {    HDC hdc;    PAINTSTRUCT ps;    hdc = BeginPaint(hwnd,&ps);   // Is there a function that allows me to change the shape of my hwnd?   // Create Circular window    HRGN foo = CreateEllipticRgn(0,0,100,100);    HBRUSH bgBrush  = CreateSolidBrush(RGB(255,0,255));    FillRgn(hdc,foo,bgBrush);    EndPaint(hwnd,&ps);    }   break;    case WM_LBUTTONDOWN:    {    MessageBox(hwnd,"You clicked me","Notify",MB_OK);    InvalidateRect(hwnd,NULL,true);    UpdateWindow(hwnd);    }    break;    case WM_NCDESTROY:    free(cc);    break;    default:    break;   }   return DefWindowProc(hwnd, msg, wParam, lParam);}
  SetWindowRgn will do that. That means after setting an ellipsic region the window will have round edges.Also note you need to destroy the region you created with DeleteObject (unless you call SetWindowRgn).   ;  Thanks :)I have made my control elliptical which is cool but I change the window shape to circular in the WM_CREATE event. Is this the best place to do this or should I do it in the WM_PAINT event?Also I want to change the background colour of my control but there is no function GetClientRegion() function so I cant do this:case WM_PAINT:    HDC hdc;    PAINTSTRUCT ps;    hdc = BeginPaint(hwnd,&ps);   HRGN foo;    GetClientRgn(hwnd,&foo); // As far as I know this function doesn't exist    HBRUSH bgBrush  = CreateSolidBrush(RGB(255,0,255));    FillRgn(hdc,&foo,bgBrush);   EndPaint(hwnd,&ps);break;Is the only way to change the background colour like this:case WM_NCCREATE:    {    cc = (CustomControl*)malloc(sizeof(CustomControl));   if (cc==false) {   MessageBox(NULL,"Failed to create CustomControl window","Error",MB_OK|MB_ICONERROR);   return 0;    }   SetWindowLong(hwnd,0,(LONG)cc); // Attach custom class to this window.   // Create Circular window    HRGN foo = CreateEllipticRgn(0,0,100,100);    SetWindowRgn(hwnd,foo,true);    }break;case WM_PAINT:    HDC hdc;    PAINTSTRUCT ps;    hdc = BeginPaint(hwnd,&ps);   RECT foo;    GetClientRect(hwnd,&foo);    HBRUSH bgBrush  = CreateSolidBrush(RGB(255,0,255));    FillRect(hdc,&foo,bgBrush);   EndPaint(hwnd,&ps);break;From what I read of the MSDN SetWindowRgn() function:"The window region determines the area within the window where the system permits drawing. The system does not display any portion of a window that lies outside of the window region."So the window is still rectangular, but only the circular HRGN is visible, so does that mean the only way to fill the window with a colour is to use a RECT not a HRGN?   ;  You don't need a GetClientRegion() function. The way it works is that for a single instance of a custom control that you want to be non-rectangular, you need to call SetWindowRgn() exactly once, so do it in WM_CREATE or just after you call CreateWindow but definitely don't do it in WM_PAINT. You pass SetWindowRgn() an HRGN that determines the shape of the window. That region should be relative to the upper left hand corner of the window rect i.e. point (0,0) of the region maps to point (r.left,r.top) if r was filled with GetWindowRect().After you call SetWindowRgn I believe Win32 owns the region you gave it, so don't call DeleteObject on it, and after you call SetWindowRgn the window's clipping region is then after changed to the shape that you provided. So if you, say, paint the rect returned by GetClientRect() in WM_PAINT it will automatically clip to the region without you doing anything.SetWindowRgn() is actually *very* easy to use.[Edited by - jwezorek on April 15, 2010 4:31:32 AM];  What jwezorek said, you do not need to manually clip drawing to the region at all once you called SetWindowRgn.Here's a function that might come in handy, in converts a HBITMAP with a color key into a HRGN (useful for complex shapes):HRGN CWinUtils::BitmapToRegion( HBITMAP hBmp, COLORREF cTransparentColor ){  HRGN hRgn = NULL;  if ( hBmp == NULL )  {    return NULL;  }  // Create a memory DC inside which we will scan the bitmap content  HDC hMemDC = CreateCompatibleDC( NULL );  if ( hMemDC == NULL )  {    return NULL;  }  // Get bitmap size  BITMAP bm;  GetObject( hBmp, sizeof( bm ), &bm );  // Create a 32 bits depth bitmap and select it into the memory DC  BITMAPINFOHEADER RGB32BITSBITMAPINFO =  {    sizeof(BITMAPINFOHEADER), // biSize    bm.bmWidth,    // biWidth;    bm.bmHeight,   // biHeight;    1,    // biPlanes;    32,   // biBitCount    BI_RGB, // biCompression;    0,    // biSizeImage;    0,    // biXPelsPerMeter;    0,    // biYPelsPerMeter;    0,    // biClrUsed;    0   // biClrImportant;  };  void*   pbits32;  HBITMAP hbm32 = CreateDIBSection( hMemDC, (BITMAPINFO*)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0 );  if ( hbm32 == NULL )  {    DeleteDC( hMemDC );    return NULL;  }  HBITMAP holdBmp = (HBITMAP)SelectObject( hMemDC, hbm32 );  // Create a DC just to copy the bitmap into the memory DC  HDC hDC = CreateCompatibleDC( hMemDC );  if ( hDC )  {    // Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits)    BITMAP    bm32;    GetObject( hbm32, sizeof( bm32 ), &bm32 );    while ( bm32.bmWidthBytes % 4 )    { bm32.bmWidthBytes++;    }    // Copy the bitmap into the memory DC    HBITMAP holdBmp = (HBITMAP)SelectObject( hDC, hBmp );    BitBlt( hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY );    // For better performances, we will use the ExtCreateRegion() function to create the    // region. This function take a RGNDATA structure on entry. We will add rectangles by    // amount of ALLOC_UNIT number in this structure.    GR::u32 maxRects = 100;    HANDLE hData = GlobalAlloc( GMEM_MOVEABLE, sizeof( RGNDATAHEADER ) + ( sizeof( RECT ) * maxRects ) );    RGNDATA *pData = (RGNDATA*)GlobalLock( hData );    pData->rdh.dwSize = sizeof( RGNDATAHEADER );    pData->rdh.iType  = RDH_RECTANGLES;    pData->rdh.nCount = pData->rdh.nRgnSize = 0;    SetRect( &pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0 );    // Keep on hand highest and lowest values for the "transparent" pixels    // Scan each bitmap row from bottom to top (the bitmap is inverted vertically)    BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;    for (int y = 0; y < bm.bmHeight; y++)    { // Scan each bitmap pixel from left to right for (int x = 0; x < bm.bmWidth; x++) {   // Search for a continuous range of "non transparent pixels"   int x0 = x;   LONG *p = (LONG *)p32 + x;   while (x < bm.bmWidth)   {if ( *p == cTransparentColor ){  // This pixel is "transparent"  break;}p++;x++;   }   if (x > x0)   {// Add the pixels (x0, y) to (x, y+1) as a new rectangle in the regionif (pData->rdh.nCount >= maxRects){  GlobalUnlock(hData);  maxRects += 100;  hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);  pData = (RGNDATA *)GlobalLock(hData);}RECT *pr = (RECT *)&pData->Buffer;SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);if (x0 < pData->rdh.rcBound.left)  pData->rdh.rcBound.left = x0;if (y < pData->rdh.rcBound.top)  pData->rdh.rcBound.top = y;if (x > pData->rdh.rcBound.right)  pData->rdh.rcBound.right = x;if (y+1 > pData->rdh.rcBound.bottom)  pData->rdh.rcBound.bottom = y+1;pData->rdh.nCount++;// On Windows98, ExtCreateRegion() may fail if the number of rectangles is too// large (ie: > 4000). Therefore, we have to create the region by multiple steps.if (pData->rdh.nCount == 2000){  HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);  if (hRgn)  {    CombineRgn(hRgn, hRgn, h, RGN_OR);    DeleteObject(h);  }  else    hRgn = h;  pData->rdh.nCount = 0;  SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);}   } } // Go to next row (remember, the bitmap is inverted vertically) p32 -= bm32.bmWidthBytes;    }    // Create or extend the region with the remaining rectangles    HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);    if (hRgn)    { CombineRgn(hRgn, hRgn, h, RGN_OR); DeleteObject(h);    }    else hRgn = h;    // Clean up    SelectObject(hDC, holdBmp);    DeleteDC(hDC);    GlobalUnlock( hData );    GlobalFree( hData );  }  DeleteObject(SelectObject(hMemDC, holdBmp));  DeleteDC( hMemDC );  return hRgn;}